Trigger not working when inserting multiple records - sql-server

I have the following trigger working correctly when I insert one record on table Pedidos.
However, when I insert multiple records I get a 512 error message. I've searched around for details about inserting multiple records and triggers, but not found an answer to my problem.
The trigger reads the inserted records and finds values from other tables to modify the value of the column situacion in table planificaciones.
Am I totally wrong in the way I'm trying to do this? Is there any obvious problems in my trigger?
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA ON dbo.pedidos after insert as begin if ##ROWCOUNT = 0
return
set nocount on
declare #v_idpla int,
#v_situacion nvarchar(12),
#v_nombre nvarchar(50),
#v_almacen nvarchar(50),
#v_status_pedido nvarchar(4);
set #v_almacen = (select almacen_pedido from inserted);
set #v_nombre =(select cliente from inserted);
set #v_status_pedido = (select status_pedido from inserted);
set #v_situacion = (select top 1 nombre from dbo.StatusPlanificacion
where STATUS_PEDIDO = #v_status_pedido);
set #v_idpla = (select top 1 id from dbo.Planificaciones
where dia_entrega >= GETDATE() and situacion <> 'Departed'
and nombre like '%'+#v_almacen +'%'+ #v_nombre);
if(#v_idpla is not null)
begin
--select Timespan=SYSDATETIME() from inserted;
select ##rowcount;
UPDATE DBO.Planificaciones
SET situacion = #v_situacion
WHERE id = #v_idpla;
end
end
UPDATE & SOLVED: Looking on tanner suggestion i do the next update on code and works, but i think some one can find this more clear and useful. In suggested by tanner, says cursor not best way to do this and the best option is a Join. In my case this insert never goes more than 50 inserts at same time.
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA
ON dbo.pedidos
after insert as
begin
declare #v_idpla int,#v_situacion nvarchar(12),#v_nombre nvarchar(50),#v_almacen nvarchar(50), #v_status_pedido nvarchar(4)
DECLARE c_cursor CURSOR FAST_FORWARD FOR SELECT ALMACEN_PEDIDO, CLIENTE, STATUS_PEDIDO FROM INSERTED;
OPEN c_cursor
fetch next from c_cursor into #v_almacen,#v_nombre,#v_status_pedido
--declared and open cursor chargin values to variables
while ##fetch_status = 0
begin
-- set values to variables from anothers tables
set #v_situacion = (select top 1 nombre from dbo.StatusPlanificacion where STATUS_PEDIDO = #v_status_pedido);
set #v_idpla = (select top 1 id from dbo.Planificaciones where dia_entrega >= GETDATE() and
situacion <> 'Departed' and nombre like '%'+#v_almacen +'%'+ #v_nombre);
--check value not null for assigned variable and do update to the value
if(#v_idpla is not null)
begin
UPDATE DBO.Planificaciones
SET situacion = #v_situacion
WHERE id = #v_idpla;
end
--move to the next row of cursor
fetch next from c_cursor into #v_almacen,#v_nombre,#v_status_pedido
end
CLOSE c_cursor
DEALLOCATE c_cursor
end

Not sure if the code is 100% correct but should give you an idea..
inserted is a dataset with all rows of that batch. You just need to think as set based operation.
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA
ON dbo.pedidos
AFTER INSERT
AS
BEGIN
UPDATE p
SET
situacion = i.nombre
FROM DBO.Planificaciones p
INNER JOIN (
SELECT
v_idpla.id
v_situacion.nombre
FROM INSERTED I
CROSS APPLY (
select top 1
SP.nombre
from dbo.StatusPlanificacion SP
where
SP.STATUS_PEDIDO = I.STATUS_PEDIDO
) v_situacion
CROSS APPLY (
select top 1
Pla.id
from dbo.Planificaciones Pla
where
Pla.dia_entrega >= GETDATE() and
Pla.situacion <> 'Departed' and
Pla.nombre like '%'+I.ALMACEN_PEDIDO +'%'+ I.CLIENTE
) v_idpla
) I ON
P.id = I.id
END

Related

insert data into sql table and get recent inserted iD and insert data in same table from different table

Here is the situation that I have to insert profile photos in the SQL table. But here are 2 scenarios the condition
if user is inserting photo and data from front end. Its working perfectly fine.
if user is skip the photo and just inserting his biography then in that case the default image should be inserted by default. I tried to do in front end Just adding dummy image in if else condition, but in DMZ server for some reason this is creating problem, on local server its working good.
Here is the Query...
ALTER PROCEDURE [dbo].[SavePhysicianBiodata]
-- Add the parameters for the stored procedure here
#ID int,
#Physician_Bio nvarchar(MAX),
#Physician_Mnemonic nvarchar(MAX),
#Physician_Image image,
#Physician_ImageType nvarchar(MAX),
#Physician_ImageFileName nvarchar(MAX)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
if( #ID is null OR #ID='')
begin
--if not image then deafult image will be applied
if((#Physician_ImageType is null or #Physician_ImageType='') and
(#Physician_ImageFileName is null or #Physician_ImageFileName='') )
begin
insert into Physician_Biodata(Physician_Bio, Physician_Mnemonic)
values(#Physician_Bio, #Physician_Mnemonic)
set #ID = SCOPE_IDENTITY()
update [dbo].[Physician_Biodata]
set Physician_Image=#Physician_Image,
Physician_ImageType=#Physician_ImageType,
Physician_ImageFileName=#Physician_ImageFileName
where ID=#ID
end
else
begin
-- Insert statements for procedure here when user adds photo as well
insert into Physician_Biodata(Physician_Bio, Physician_Mnemonic,
Physician_Image, Physician_ImageType, Physician_ImageFileName)
values(#Physician_Bio, #Physician_Mnemonic,
#Physician_Image,#Physician_ImageType,#Physician_ImageFileName)
end
end
else
begin
update [dbo].[Physician_Biodata]
set Physician_Bio=#Physician_Bio,
Physician_Mnemonic=#Physician_Mnemonic,
Physician_Image=#Physician_Image,
Physician_ImageType=#Physician_ImageType,
Physician_ImageFileName=#Physician_ImageFileName
where ID=#ID
end
END
In this query I also tried insert query which is given below
insert into Physician_Biodata(ID, Physician_Image, Physician_ImageType, Physician_ImageFileName)
select #ID, dd.Physician_Image,dd.Physician_ImageType,dd.Physician_ImageFileName from DefaultImage as dd
join Physician_Biodata
on Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
where Physician_Biodata.ID = #ID
but getting error during execute procedure
Msg 544, Level 16, State 1, Procedure dbo.SavePhysicianBiodata, Line 35 [Batch Start Line 2]
Cannot insert explicit value for identity column in table 'Physician_Biodata' when IDENTITY_INSERT is set to OFF.
If somebody can help me it would be great.. Thanks in advance.
Yes I have already changed the first insert statement (removed ID) and
updated the 2nd query
set #ID = IDENT_CURRENT('Physician_Biodata')
update Physician_Biodata
set Physician_Biodata.Physician_Image= DefaultImage.Physician_Image, Physician_Biodata.Physician_ImageType= DefaultImage.Physician_ImageType, Physician_Biodata.Physician_ImageFileName=DefaultImage.Physician_ImageFileName from Physician_Biodata, DefaultImage where Physician_Biodata.ID=#ID
and it worked
It appears that Physician_Biodata's ID column is an IDENTITY, hence the exception you have.
Changing this...
INSERT INTO Physician_Biodata (
ID, Physician_Image, Physician_ImageType, Physician_ImageFileName
)
SELECT
#ID,
dd.Physician_Image,
dd.Physician_ImageType,
dd.Physician_ImageFileName
FROM DefaultImage AS dd
JOIN Physician_Biodata
ON Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
WHERE
Physician_Biodata.ID = #ID;
To this...
INSERT INTO Physician_Biodata (
Physician_Image, Physician_ImageType, Physician_ImageFileName
)
SELECT
dd.Physician_Image,
dd.Physician_ImageType,
dd.Physician_ImageFileName
FROM DefaultImage AS dd
JOIN Physician_Biodata
ON Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
WHERE
Physician_Biodata.ID = #ID;
Will make your "explicit value" exception go away as in your INSERT you are attempting to insert #ID into ID which is an identity column. You also use ID = #ID in your WHERE clause, which makes inserting #ID pointless as this would be a chicken-and-egg issue.
On another note, if #Physician_ImageType and #Physician_ImageFileName are both NULL going in, they'll still be NULL on your UPDATE given your existing SP's logic.
I've taken a little liberty to tidy/simplify your T-SQL and added a note about what I've questioned.
ALTER PROCEDURE [dbo].[SavePhysicianBiodata] (
#ID int,
#Physician_Bio nvarchar(MAX),
#Physician_Mnemonic nvarchar(MAX),
#Physician_Image image,
#Physician_ImageType nvarchar(MAX),
#Physician_ImageFileName nvarchar(MAX)
)
AS
BEGIN
SET NOCOUNT ON;
IF ISNULL( #ID, '' ) = ''
BEGIN
--if not image then deafult image will be applied
IF ISNULL( #Physician_ImageType, '' ) = '' AND ISNULL( #Physician_ImageFileName, '' ) = ''
BEGIN
INSERT INTO Physician_Biodata ( Physician_Bio, Physician_Mnemonic )
VALUES ( #Physician_Bio, #Physician_Mnemonic ) ;
SET #ID = SCOPE_IDENTITY();
/*
Where are you setting the values for #Physician_Image, #Physician_ImageType, and #Physician_ImageFileName? These are still NULL?
*/
UPDATE [dbo].[Physician_Biodata]
SET
Physician_Image = #Physician_Image,
Physician_ImageType = #Physician_ImageType,
Physician_ImageFileName = #Physician_ImageFileName
WHERE
ID = #ID;
END
ELSE BEGIN
-- Insert statements for procedure here when user adds photo as well
INSERT INTO Physician_Biodata (
Physician_Bio, Physician_Mnemonic, Physician_Image, Physician_ImageType, Physician_ImageFileName
)
VALUES (
#Physician_Bio, #Physician_Mnemonic, #Physician_Image, #Physician_ImageType, #Physician_ImageFileName
);
END
END
ELSE BEGIN
UPDATE [dbo].[Physician_Biodata]
SET
Physician_Bio = #Physician_Bio,
Physician_Mnemonic = #Physician_Mnemonic,
Physician_Image = #Physician_Image,
Physician_ImageType = #Physician_ImageType,
Physician_ImageFileName = #Physician_ImageFileName
WHERE
ID = #ID;
END
END

Same query, same database, different server, different result

We have our main database on a server, there is this stored procedure; when we run it against the database, it returns wrong values.
But when I take a back up of this database and restore it on another server and run the exact same query, it returns the correct answer.
What can I do?
Is it possible that the configuration of SQL Server affects how a query returns results?
If yes where can I start looking for problem ?
Here is the stored procedure, the exact same procedure runs on both databases and both databases are identical.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[S_GheymatGozaryFIFOFroosh]
#AYear SMALLINT,
#LDate CHAR(8),
#OdCd VARCHAR(17),
#FromFirst BIT,
#SCd TINYINT
AS
DECLARE #LHId Int, #LHRadif SmallInt,
#LHFact_Date CHAR(8), #LHFact_No INT,
#LHStock_Cd TinyInt, #LQnt_Resid DECIMAL(18,4),
#LPrc_Resid DECIMAL(30,8)
DECLARE #LRId INT, #LRRadif SmallInt,
#LRFact_Date CHAR(8), #LRFact_No INT,
#LRStock_Cd TinyInt
DECLARE #Kind_Cd TINYINT, #StartDate CHAR(8)
DECLARE #Cnt INT
SET #Cnt = 0
IF #ldate IS NOT NULL AND #FromFirst = 1
BEGIN
DELETE FROM S_Fifo_Gheymat
WHERE (Acc_Year = #Ayear)
AND (#SCd = 0 OR H_Stock_Cd = #SCd)
AND (Od_Cd = #OdCd)
END
IF #SCd = 0
SET #Kind_Cd = 2
ELSE
SET #Kind_Cd = 1
SET #StartDate = Right(CAST(#AYear AS VARCHAR(4)), 2) + '/01/01'
SELECT
#LHId = H_Id,
#LHRadif = H_Radif,
#LHFact_Date = H_Fact_Date,
#LHFact_No = H_Fact_No,
#LHStock_Cd = H_Stock_Cd,
#LQnt_Resid = Qnt_Resid,
#LPrc_Resid = Prc_Resid,
#LRId = R_Id,
#LRRadif = R_Radif,
#LRFact_Date = R_Fact_Date,
#LRFact_No = R_Fact_No,
#LRStock_Cd = R_Stock_Cd
FROM
S_Fifo_Gheymat
WHERE
Acc_Year = #AYear
AND Od_Cd = #OdCd
AND (#SCd = 0 OR H_Stock_Cd = #SCd)
AND EXISTS (SELECT Id
FROM S_Dtl_Fct
WHERE Id = H_Id
AND Radif = H_Radif
AND Stock_Cd = H_Stock_Cd
AND Od_Cd = S_Fifo_Gheymat.Od_Cd)
AND EXISTS (SELECT Id
FROM S_Dtl_Fct
WHERE Id = R_Id
AND Radif = R_Radif
AND Stock_Cd = R_Stock_Cd
AND Od_Cd = S_Fifo_Gheymat.Od_Cd)
SELECT #LHId=ISNULL(#LHId,0),#LHRadif=IsNull(#LHRadif,0),#LHFact_Date=IsNull
(#LHFact_Date,#StartDate),#LHFact_No=IsNull(#LHFact_No,0),#LHStock_Cd=ISNULL
(#LHStock_Cd,0)
,#LQnt_Resid=ISNULL(#LQnt_Resid,0),#LPrc_Resid=ISNULL(#LPrc_Resid,0)
,#LRId=ISNULL(#LRId,0),#LRRadif=IsNull(#LRRadif,0),#LRFact_Date=IsNull
(#LRFact_Date,#StartDate),#LRFact_No=IsNull(#LRFact_No,0),#LRStock_Cd=ISNULL
(#LRStock_Cd,0)
---------------------------------------
IF #LDate IS NULL BEGIN
SELECT TOP 1 #LDate=Fact_Date
FROM S_Dtl_Fct D
LEFT OUTER JOIN S_Hed_Fct H ON D.Id=H.Id
LEFT OUTER JOIN dbo.S_STOCKS S ON D.Stock_Cd=S.Stock_Cd
LEFT OUTER JOIN U_Log U ON H.Id_Log=U.Id_Log AND U.Action_Cd=5
WHERE (H.Acc_Year=#AYear) AND (H.Flag=6) AND (D.Od_Cd=#OdCd) AND
(H.Tamam=0) AND (#SCd<>0 OR S.Estesna_Gp=0)
AND (
(H.Fact_Date>#LHFact_Date)
OR (H.Fact_Date=#LHFact_Date AND
H.Fact_No>#LHFact_No)
OR (H.Fact_Date=#LHFact_Date AND
H.Fact_No=#LHFact_No AND D.Radif>#LHRadif)
OR (H.Fact_Date=#LHFact_Date AND
H.Fact_No=#LHFact_No AND D.Radif=#LHRadif AND D.Stock_Cd>#LHStock_Cd)
)
AND (#SCd=0 OR D.Stock_Cd=#SCd) AND (H.VAZEIAT<>2) AND
(U.Id_Log IS NOT NULL)
ORDER BY H.Fact_Date
End
DECLARE #H TABLE ( H_Id INT,H_Radif SMALLINT,H_Fact_Date CHAR
(8),H_Fact_No INT,H_Stock_Cd TINYINT,Quantity Decimal(18,4),Un_Prc
MONEY,HTamam Bit
,R_Id INT,R_Radif SMALLINT,R_Fact_Date
CHAR(8),R_Fact_No INT,R_Stock_Cd TINYINT,Qnt_Resid Decimal(18,2),Prc_Resid
Decimal(30,8))
INSERT INTO #H
(H_Id,H_Radif,H_Fact_Date,H_Fact_No,H_Stock_Cd,Quantity,HTamam)
SELECT D.Id,D.Radif,H.Fact_Date,H.Fact_No,D.Stock_Cd,D.Quantity,H.Tamam
FROM S_Dtl_Fct D
LEFT OUTER JOIN S_Hed_Fct H ON D.Id=H.Id
LEFT OUTER JOIN dbo.S_STOCKS S ON D.Stock_Cd=S.Stock_Cd
WHERE (H.Acc_Year=#AYear) AND (H.Flag=6) AND (D.Od_Cd=#OdCd) AND
(H.Fact_Date<=#LDate) AND (#SCd<>0 OR S.Estesna_Gp=0)
AND (
(H.Fact_Date>#LHFact_Date)
OR (H.Fact_Date=#LHFact_Date AND H.Fact_No>#LHFact_No)
OR (H.Fact_Date=#LHFact_Date AND H.Fact_No=#LHFact_No
AND D.Radif>#LHRadif)
OR (H.Fact_Date=#LHFact_Date AND H.Fact_No=#LHFact_No
AND D.Radif=#LHRadif AND D.Stock_Cd>#LHStock_Cd)
)
AND (#SCd=0 OR D.Stock_Cd=#SCd) AND (H.VAZEIAT<>2)
ORDER BY H.Fact_Date,H.Fact_No,D.Radif,D.Stock_Cd
Delete S_Related_RH FROM #H H LEFT OUTER JOIN S_Related_RH R ON
H.H_Id=R.H_Id AND H.H_Radif=R.H_Radif
------------------------------------------
DECLARE #HQnt DECIMAL(18,4),#HDate CHAR(8),#SumQ DECIMAL(18,4),#SumG
MONEY,#HQntWithPrc DECIMAL(18,4)
SET #SumG=#LQnt_Resid*#LPrc_Resid
SET #SumQ=#LQnt_Resid
--
DECLARE Cr CURSOR FOR SELECT Quantity,H_Fact_Date,H_Id,H_Radif FROM #H FOR
UPDATE OF Un_Prc
Open Cr
Fetch Next From Cr InTo #HQnt,#HDate,#LHId,#LHRadif
While (##Fetch_Status=0) AND (#LRId IS NOT NULL)
Begin
IF #HQnt<=#LQnt_Resid BEGIN
SET #LQnt_Resid=#LQnt_Resid-#HQnt
UPDATE #H SET
Un_Prc=#SumG/#SumQ,R_Id=#LRId,R_Radif=#LRRadif,R_Fact_Date=#LRFact_Date,
R_Fact_No=#LRFact_No,R_Stock_Cd=#LRStock_Cd
,Qnt_Resid=#LQnt_Resid,Prc_Resid=#LPrc_Resid
WHERE CURRENT OF Cr
IF #HQnt>0 BEGIN
INSERT INTO dbo.S_Related_RH
(H_Id,H_Radif,R_Id,R_Radif,Quantity)
VALUES (#LHId,#LHRadif,#LRId,#LRRadif,#HQnt)
END
SET #SumG=#LQnt_Resid*#LPrc_Resid
SET #SumQ=#LQnt_Resid
Fetch Next From Cr InTo #HQnt,#HDate,#LHId,#LHRadif
END ELSE BEGIN
IF #LQnt_Resid>0 BEGIN
INSERT INTO dbo.S_Related_RH
(H_Id,H_Radif,R_Id,R_Radif,Quantity)
VALUES (#LHId,#LHRadif,#LRId,#LRRadif,#LQnt_Resid)
END
SET #HQnt=#HQnt-#LQnt_Resid --مقدار باقیمانده حواله
SELECT TOP 1
#LRId=D.Id,#LRRadif=D.Radif,#LRFact_Date=H.Fact_Date,#LRFact_No=H.Fact_No,
#LRStock_Cd=D.Stock_Cd,#LQnt_Resid=D.QUANTITY
,#LPrc_Resid=CASE D.QUANTITY WHEN 0
THEN 0 ELSE ( (Un_Prc*D.QUANTITY)+ISNULL(Qnt_1,0) )/ D.QUANTITY END
FROM S_Dtl_Fct D
LEFT OUTER JOIN S_Hed_Fct H ON D.Id=H.Id
LEFT OUTER JOIN dbo.S_STOCKS S ON D.Stock_Cd=S.Stock_Cd
WHERE (H.Acc_Year=#AYear) AND (H.Flag=5) AND (D.Od_Cd=#OdCd)
AND (H.Fact_Date<=#HDate) AND (H.Tamam=1) AND (#SCd<>0 OR S.Estesna_Gp=0)
AND (
(H.Fact_Date>#LRFact_Date)
OR (H.Fact_Date=#LRFact_Date AND
H.Fact_No>#LRFact_No)
OR (H.Fact_Date=#LRFact_Date AND
H.Fact_No=#LRFact_No AND D.Radif>#LRRadif)
OR (H.Fact_Date=#LRFact_Date AND
H.Fact_No=#LRFact_No AND D.Radif=#LRRadif AND D.Stock_Cd>#LRStock_Cd)
)
AND (#SCd=0 OR D.Stock_Cd=#SCd) AND (H.VAZEIAT<>2)
ORDER BY H.Fact_Date,H.Fact_No,D.Radif,D.Stock_Cd
--
IF #LRId IS NOT NULL BEGIN
IF #HQnt<=#LQnt_Resid SET #HQntWithPrc=#HQnt ELSE SET
#HQntWithPrc=#LQnt_Resid
SET #SumG=#SumG+(#HQntWithPrc*#LPrc_Resid)
SET #SumQ=#SumQ+#HQntWithPrc
End
IF ISNULL(#LQnt_Resid,0)=0 Break
End
END
Close Cr
Deallocate Cr
DECLARE #E Int
SET #E=0
BEGIN TRAN
UPDATE D SET Un_Prc=G.Un_Prc
FROM S_Dtl_Fct D
INNER JOIN #H G ON D.Id=G.H_Id AND D.Radif=G.H_Radif
WHERE (G.HTamam=0) And (G.R_Id IS NOT NULL)
SET #Cnt=##ROWCOUNT
Set #E=#E+##Error
DELETE F FROM S_Fifo_Gheymat F
WHERE (Acc_Year=#Ayear) AND (#SCd=0 OR H_Stock_Cd=#SCd) AND
(Od_Cd=#OdCd)
And EXISTS (SELECT TOP 1 Od_Cd
FROM #H
WHERE (H_Stock_Cd=F.H_Stock_Cd) AND
(Od_Cd=#OdCd) AND (R_Id IS NOT NULL)
ORDER BY H_Fact_Date DESC ,H_Fact_No
DESC ,H_Radif DESC ,H_Stock_Cd DESC)
Set #E=#E+##Error
INSERT INTO S_Fifo_Gheymat
(Acc_Year,H_Stock_Cd,OD_CD,R_Stock_Cd,H_Id,H_Fact_Date,H_Fact_No,
H_Radif,R_Id,R_Fact_Date,R_Fact_No,R_Radif,Qnt_Resid,Prc_Resid)
SELECT TOP 1
#AYear,H_Stock_Cd,#OdCd,R_Stock_Cd,H_Id,H_Fact_Date,H_Fact_No,H_Radif,
R_Id,R_Fact_Date,R_Fact_No,R_Radif,Qnt_Resid,Prc_Resid
FROM #H
WHERE R_Id IS NOT Null
ORDER BY H_Fact_Date DESC ,H_Fact_No DESC ,H_Radif DESC ,H_Stock_Cd Desc
Set #E=#E+##Error
IF #E=0 COMMIT TRAN ELSE ROLLBACK TRAN
SELECT #Cnt Cnt,#LHFact_No LHFactNo,#LHFact_Date LHFactDate,#LHStock_Cd
LHStock_Cd,#LRFact_No LRFactNo,#LRFact_Date LRFactDate,#LRStock_Cd
LRStock_Cd
Without a copy of your db (not a request) it's not possible to answer this.
Is it possible that the configuration of SQL Server affects how a
query returns results?
Yes this is a possibility. For example, if your ANSI NULL settings are different between the two servers then NULL will be equal to NULL on the server has ANSI_NULL set to on OFF but not on the server where ANSI_NULL is ON. Collation is another. If one server has a case sensitive collation the "A" and "a" are not equal whereas the opposite is true using the SQL Server default. These are just a couple examples.
That said, they way to isolate the problem is to break the stored proc up into parts and try to identify where the differences are starting. In the first steps, where you assign variables, add a step to dump them into a temp table that you can summarize and compare across both servers. If there's no differences keep moving down the proc running each part until you find a difference. Often I'll comment everything out then uncomment code from top-to-bottom until I isolate the problem.
Lastly, you are using couple cursors here and don't need to. You can simplify your code by making it more set-based and therefore less verbose. It will be much easier to troubleshoot and will perform much, much better.

exactly what trigger doesn't work

friends I'm writing a trigger, but there is something I missed or did I get it wrong I don't know.
the problem is probably with the code to get the code I wrote There is a problem. But I wasn't sure.
the purpose of the inventory when he enters the trigger, add it to the part of your debt when you remove the pieces.
when added Act the same way
create trigger StokHareketGirisCikis
on StokHareket
after insert,update,delete
as
declare #stokKodu nvarchar(50),#gc int,#stokId int,#adet int
if exists (select * from deleted)
begin
select #stokId=id from deleted
select #stokKodu=(select StokKodu from StokKarti where id=#stokId),#adet=Miktar,#gc=GC from deleted
if #gc=1
begin
update StokToplam set borc-=#adet where stokKodu=#stokKodu
end
else
update StokToplam set alacak-=#adet where stokKodu=#stokKodu
end
if exists(select * from inserted)
begin
select #stokId=id from inserted
select #stokKodu=(select StokKodu from StokKarti where id=#stokId),#adet=Miktar,#gc=GC from inserted
if #gc=1
begin
update StokToplam set borc+=#adet where stokKodu=#stokKodu
end
else
update StokToplam set alacak+=#adet where stokKodu=#stokKodu
end
The main problem is you are using 1 row (f.e. select #stokId=id from deleted), but there maybe more rows in inserted and deleted. You don't need to use variables to take values from this tables, use JOIN.
F.e. this part:
select #stokId=id from deleted
select #stokKodu=(select StokKodu from StokKarti where id=#stokId),#adet=Miktar,#gc=GC from deleted
if #gc=1
begin
update StokToplam set borc-=#adet where stokKodu=#stokKodu
end
else
update StokToplam set alacak-=#adet where stokKodu=#stokKodu
Could be rewrited like:
;WITH cte AS (
select sk.StokKodu,
d.Miktar,
d.GC
from deleted d
inner join StokKarti sk
ON sk.id = d.id
)
update st
set borc-=c.Miktar
FROM StokToplam st
INNER JOIN cte с
ON c.stokKodu=st.stokKodu
AND c.GC = 1
update st
set alacak-=c.Miktar
FROM StokToplam st
INNER JOIN cte с
ON c.stokKodu=st.stokKodu
AND c.GC != 1
I took care of the problem. ' StokId ' ' StokKodu ' I changed it to. works just fine.
create trigger [dbo].[StokHareketGirisCikis]
on [dbo].[StokHareket]
after insert,update,delete
as
declare #stokKodu nvarchar(50),#gc int,#adet int
if exists (select * from deleted)
begin
select #stokKodu=StokKodu,#adet=Miktar,#gc=GC from deleted
if #gc=1
begin
update StokToplam set borc-=#adet where stokKodu=#stokKodu
end
else
update StokToplam set alacak-=#adet where stokKodu=#stokKodu
end
if exists(select * from inserted)
begin
select #stokKodu=StokKodu,#adet=Miktar,#gc=GC from inserted
if #gc=1
begin
update StokToplam set borc+=#adet where stokKodu=#stokKodu
end
else
update StokToplam set alacak+=#adet where stokKodu=#stokKodu
end
#gofr1 thank you so much

SQL Server 2012 Trigger

Hey guys thank you in advance for any help,
I have this trigger in my SQL Server 2012 database
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE dbo.textos
SET tag = UPPER(#tag)
WHERE ID_texto = #ID
END
BEGIN
UPDATE dbo.textos
SET data = GETDATE()
WHERE ID_texto = #ID
END
GO
And as you can see it should update 2 values the "tag" row and the "data" row once something is inserted in the table, however its only updating the "data" row.
If i just select this piece of code and run/debug it, it actually updates both rows, any idea why this is hapening ?
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE dbo.textos
SET tag = UPPER(#tag)
WHERE ID_texto = #ID
END
BEGIN
UPDATE dbo.textos
SET data = GETDATE()
WHERE ID_texto = #ID
END
Once again thank you in advance for your help and time.
I assume that you are performing the following query simply to get the inserted row:
SELECT MAX(ID_texto) FROM dbo.textos
That won't work, as others have pointed out. If you insert more than one row at once, only the last in the set will be modified by the trigger.
Do a JOIN on the INSERTED table to get the new rows, then another JOIN on semantickeyphrasetable(textos, *) to get the tag values. Something like this:
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
UPDATE T
SET tag = UPPER(K.keyphrase), data = GETDATE()
FROM dbo.textos T
JOIN INSERTED ON INSERTED.ID_texto = T.ID_texto
LEFT JOIN (
SELECT TOP 1 document_key, keyphrase
FROM semantickeyphrasetable(textos, *)
) K ON K.document_key=T.ID_texto
END
GO
Triggers will basically trigger once for each batch operation, so you should perform your logic based on this reality. This is also in SQL spirit, which favors (read as performs better) set based operations.
All inserted items are stored into a special table, called inserted, so you should join with this table to know what are the exact records that were touched:
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE Dest
SET tag = UPPER(#tag)
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
BEGIN
UPDATE Dest
SET data = GETDATE()
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
END
The above is not tested, but should help you get an idea on how to proceed to actually update records that were inserted.
Did this answer ever get solved?
If not, why not just add both updates in one line instead of having 2 BEGIN...END blocks?
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE Dest
SET tag = UPPER(#tag), data = GETDATE()
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
END
Use the below code. In your case I think the trigger is firing before semantickeyphrasetable TABLE insertion done. So updating nothing in first begin as #tag is empty.
Its better to put the trigger in child table.(If we need to update Parent table with child table data.)
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
DECLARE #ID INT
,#tag NVARCHAR(MAX)
SELECT #ID = ID_texto
FROM INSERTED
SET #tag = (
SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key = #ID
)
UPDATE dbo.textos
SET tag = UPPER(#tag)
,
SET data = GETDATE()
WHERE ID_texto = #ID
GO
Note: When multiple insertion done, it will fail.

Insert Update trigger how to determine if insert or update

I need to write an Insert, Update Trigger on table A which will delete all rows from table B whose one column (say Desc) has values like the value inserted/updated in the table A's column (say Col1). How would I go around writing it so that I can handle both Update and Insert cases. How would I determine if the trigger is executed for an update or insert.
Triggers have special INSERTED and DELETED tables to track "before" and "after" data. So you can use something like IF EXISTS (SELECT * FROM DELETED) to detect an update. You only have rows in DELETED on update, but there are always rows in INSERTED.
Look for "inserted" in CREATE TRIGGER.
Edit, 23 Nov 2011
After comment, this answer is only for INSERTED and UPDATED triggers.
Obviously, DELETE triggers can not have "always rows in INSERTED" as I said above
CREATE TRIGGER dbo.TableName_IUD
ON dbo.TableName
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
--
-- Check if this is an INSERT, UPDATE or DELETE Action.
--
DECLARE #action as char(1);
SET #action = 'I'; -- Set Action to Insert by default.
IF EXISTS(SELECT * FROM DELETED)
BEGIN
SET #action =
CASE
WHEN EXISTS(SELECT * FROM INSERTED) THEN 'U' -- Set Action to Updated.
ELSE 'D' -- Set Action to Deleted.
END
END
ELSE
IF NOT EXISTS(SELECT * FROM INSERTED) RETURN; -- Nothing updated or inserted.
...
END
Many of these suggestions do not take into account if you run a delete statement that deletes nothing.
Say you try to delete where an ID equals some value that does not exist in the table.
Your trigger still gets called but there is nothing in the Deleted or Inserted tables.
Use this to be safe:
--Determine if this is an INSERT,UPDATE, or DELETE Action or a "failed delete".
DECLARE #Action as char(1);
SET #Action = (CASE WHEN EXISTS(SELECT * FROM INSERTED)
AND EXISTS(SELECT * FROM DELETED)
THEN 'U' -- Set Action to Updated.
WHEN EXISTS(SELECT * FROM INSERTED)
THEN 'I' -- Set Action to Insert.
WHEN EXISTS(SELECT * FROM DELETED)
THEN 'D' -- Set Action to Deleted.
ELSE NULL -- Skip. It may have been a "failed delete".
END)
Special thanks to #KenDog and #Net_Prog for their answers.
I built this from their scripts.
I'm using the following, it also correctly detect delete statements that delete nothing:
CREATE TRIGGER dbo.TR_TableName_TriggerName
ON dbo.TableName
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS(SELECT * FROM INSERTED)
-- DELETE
PRINT 'DELETE';
ELSE
BEGIN
IF NOT EXISTS(SELECT * FROM DELETED)
-- INSERT
PRINT 'INSERT';
ELSE
-- UPDATE
PRINT 'UPDATE';
END
END;
Declare #Type varchar(50)='';
IF EXISTS (SELECT * FROM inserted) and EXISTS (SELECT * FROM deleted)
BEGIN
SELECT #Type = 'UPDATE'
END
ELSE IF EXISTS(SELECT * FROM inserted)
BEGIN
SELECT #Type = 'INSERT'
END
ElSE IF EXISTS(SELECT * FROM deleted)
BEGIN
SELECT #Type = 'DELETE'
END
I believe nested ifs a little confusing and:
Flat is better than nested [The Zen of Python]
;)
DROP TRIGGER IF EXISTS AFTER_MYTABLE
GO
CREATE TRIGGER dbo.AFTER_MYTABLE ON dbo.MYTABLE AFTER INSERT, UPDATE, DELETE
AS BEGIN
--- FILL THE BEGIN/END SECTION FOR YOUR NEEDS.
SET NOCOUNT ON;
IF EXISTS(SELECT * FROM INSERTED) AND EXISTS(SELECT * FROM DELETED)
BEGIN PRINT 'UPDATE' END
ELSE IF EXISTS(SELECT * FROM INSERTED) AND NOT EXISTS(SELECT * FROM DELETED)
BEGIN PRINT 'INSERT' END
ELSE IF EXISTS(SELECT * FROM DELETED) AND NOT EXISTS(SELECT * FROM INSERTED)
BEGIN PRINT 'DELETED' END
ELSE BEGIN PRINT 'NOTHING CHANGED'; RETURN; END -- NOTHING
END
After a lot of searching I could not find an exact example of a single SQL Server trigger that handles all (3) three conditions of the trigger actions INSERT, UPDATE, and DELETE. I finally found a line of text that talked about the fact that when a DELETE or UPDATE occurs, the common DELETED table will contain a record for these two actions. Based upon that information, I then created a small Action routine which determines why the trigger has been activated. This type of interface is sometimes needed when there is both a common configuration and a specific action to occur on an INSERT vs. UPDATE trigger. In these cases, to create a separate trigger for the UPDATE and the INSERT would become maintenance problem. (i.e. were both triggers updated properly for the necessary common data algorithm fix?)
To that end, I would like to give the following multi-trigger event code snippet for handling INSERT, UPDATE, DELETE in one trigger for an Microsoft SQL Server.
CREATE TRIGGER [dbo].[INSUPDDEL_MyDataTable]
ON [dbo].[MyDataTable] FOR INSERT, UPDATE, DELETE
AS
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with caller queries SELECT statements.
-- If an update/insert/delete occurs on the main table, the number of records affected
-- should only be based on that table and not what records the triggers may/may not
-- select.
SET NOCOUNT ON;
--
-- Variables Needed for this Trigger
--
DECLARE #PACKLIST_ID varchar(15)
DECLARE #LINE_NO smallint
DECLARE #SHIPPED_QTY decimal(14,4)
DECLARE #CUST_ORDER_ID varchar(15)
--
-- Determine if this is an INSERT,UPDATE, or DELETE Action
--
DECLARE #Action as char(1)
DECLARE #Count as int
SET #Action = 'I' -- Set Action to 'I'nsert by default.
SELECT #Count = COUNT(*) FROM DELETED
if #Count > 0
BEGIN
SET #Action = 'D' -- Set Action to 'D'eleted.
SELECT #Count = COUNT(*) FROM INSERTED
IF #Count > 0
SET #Action = 'U' -- Set Action to 'U'pdated.
END
if #Action = 'D'
-- This is a DELETE Record Action
--
BEGIN
SELECT #PACKLIST_ID =[PACKLIST_ID]
,#LINE_NO = [LINE_NO]
FROM DELETED
DELETE [dbo].[MyDataTable]
WHERE [PACKLIST_ID]=#PACKLIST_ID AND [LINE_NO]=#LINE_NO
END
Else
BEGIN
--
-- Table INSERTED is common to both the INSERT, UPDATE trigger
--
SELECT #PACKLIST_ID =[PACKLIST_ID]
,#LINE_NO = [LINE_NO]
,#SHIPPED_QTY =[SHIPPED_QTY]
,#CUST_ORDER_ID = [CUST_ORDER_ID]
FROM INSERTED
if #Action = 'I'
-- This is an Insert Record Action
--
BEGIN
INSERT INTO [MyChildTable]
(([PACKLIST_ID]
,[LINE_NO]
,[STATUS]
VALUES
(#PACKLIST_ID
,#LINE_NO
,'New Record'
)
END
else
-- This is an Update Record Action
--
BEGIN
UPDATE [MyChildTable]
SET [PACKLIST_ID] = #PACKLIST_ID
,[LINE_NO] = #LINE_NO
,[STATUS]='Update Record'
WHERE [PACKLIST_ID]=#PACKLIST_ID AND [LINE_NO]=#LINE_NO
END
END
while i do also like the answer posted by #Alex, i offer this variation to #Graham's solution above
this exclusively uses record existence in the INSERTED and UPDATED tables, as opposed to using COLUMNS_UPDATED for the first test.
It also provides the paranoid programmer relief knowing that the final case has been considered...
declare #action varchar(4)
IF EXISTS (SELECT * FROM INSERTED)
BEGIN
IF EXISTS (SELECT * FROM DELETED)
SET #action = 'U' -- update
ELSE
SET #action = 'I' --insert
END
ELSE IF EXISTS (SELECT * FROM DELETED)
SET #action = 'D' -- delete
else
set #action = 'noop' --no records affected
--print #action
you will get NOOP with a statement like the following :
update tbl1 set col1='cat' where 1=2
DECLARE #ActionType CHAR(6);
SELECT #ActionType = COALESCE(CASE WHEN EXISTS(SELECT * FROM INSERTED)
AND EXISTS(SELECT * FROM DELETED) THEN 'UPDATE' END,
CASE WHEN EXISTS(SELECT * FROM DELETED) THEN 'DELETE' END,
CASE WHEN EXISTS(SELECT * FROM INSERTED) THEN 'INSERT' END);
PRINT #ActionType;
Try this..
ALTER TRIGGER ImportacionesGS ON dbo.Compra
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
-- idCompra is PK
DECLARE #vIdCompra_Ins INT,#vIdCompra_Del INT
SELECT #vIdCompra_Ins=Inserted.idCompra FROM Inserted
SELECT #vIdCompra_Del=Deleted.idCompra FROM Deleted
IF (#vIdCompra_Ins IS NOT NULL AND #vIdCompra_Del IS NULL)
Begin
-- Todo Insert
End
IF (#vIdCompra_Ins IS NOT NULL AND #vIdCompra_Del IS NOT NULL)
Begin
-- Todo Update
End
IF (#vIdCompra_Ins IS NULL AND #vIdCompra_Del IS NOT NULL)
Begin
-- Todo Delete
End
END
This might be a faster way:
DECLARE #action char(1)
IF COLUMNS_UPDATED() > 0 -- insert or update
BEGIN
IF EXISTS (SELECT * FROM DELETED) -- update
SET #action = 'U'
ELSE
SET #action = 'I'
END
ELSE -- delete
SET #action = 'D'
I found a small error in Grahams otherwise cool solution:
It should be
IF COLUMNS_UPDATED() <> 0 -- insert or update
instead of > 0
probably because top bit gets interpreted as SIGNED integer sign bit...(?).
So in total:
DECLARE #action CHAR(8)
IF COLUMNS_UPDATED() <> 0 -- delete or update?
BEGIN
IF EXISTS (SELECT * FROM deleted) -- updated cols + old rows means action=update
SET #action = 'UPDATE'
ELSE
SET #action = 'INSERT' -- updated columns and nothing deleted means action=insert
END
ELSE -- delete
BEGIN
SET #action = 'DELETE'
END
A potential problem with the two solutions offered is that, depending on how they are written, an update query may update zero records and an insert query may insert zero records. In these cases, the Inserted and Deleted recordsets will be empty. In many cases, if both the Inserted and Deleted recordsets are empty you might just want to exit the trigger without doing anything.
declare #insCount int
declare #delCount int
declare #action char(1)
select #insCount = count(*) from INSERTED
select #delCount = count(*) from DELETED
if(#insCount > 0 or #delCount > 0)--if something was actually affected, otherwise do nothing
Begin
if(#insCount = #delCount)
set #action = 'U'--is update
else if(#insCount > 0)
set #action = 'I' --is insert
else
set #action = 'D' --is delete
--do stuff here
End
This does the trick for me:
declare #action_type int;
select #action_type = case
when i.id is not null and d.id is null then 1 -- insert
when i.id is not null and d.id is not null then 2 -- update
when i.id is null and d.id is not null then 3 -- delete
end
from inserted i
full join deleted d on d.id = i.id
Since not all columns can be updated at a time you can check whether a particular column is being updated by something like this:
IF UPDATE([column_name])
just simple way
CREATE TRIGGER [dbo].[WO_EXECUTION_TRIU_RECORD] ON [dbo].[WO_EXECUTION]
WITH EXECUTE AS CALLER
FOR INSERT, UPDATE
AS
BEGIN
select #vars = [column] from inserted
IF UPDATE([column]) BEGIN
-- do update action base on #vars
END ELSE BEGIN
-- do insert action base on #vars
END
END
I like solutions that are "computer science elegant." My solution here hits the [inserted] and [deleted] pseudotables once each to get their statuses and puts the result in a bit mapped variable. Then each possible combination of INSERT, UPDATE and DELETE can readily be tested throughout the trigger with efficient binary evaluations (except for the unlikely INSERT or DELETE combination).
It does make the assumption that it does not matter what the DML statement was if no rows were modified (which should satisfy the vast majority of cases). So while it is not as complete as Roman Pekar's solution, it is more efficient.
With this approach, we have the possibility of one "FOR INSERT, UPDATE, DELETE" trigger per table, giving us A) complete control over action order and b) one code implementation per multi-action-applicable action. (Obviously, every implementation model has its pros and cons; you will need to evaluate your systems individually for what really works best.)
Note that the "exists (select * from «inserted/deleted»)" statements are very efficient since there is no disk access (https://social.msdn.microsoft.com/Forums/en-US/01744422-23fe-42f6-9ab0-a255cdf2904a).
use tempdb
;
create table dbo.TrigAction (asdf int)
;
GO
create trigger dbo.TrigActionTrig
on dbo.TrigAction
for INSERT, UPDATE, DELETE
as
declare #Action tinyint
;
-- Create bit map in #Action using bitwise OR "|"
set #Action = (-- 1: INSERT, 2: DELETE, 3: UPDATE, 0: No Rows Modified
(select case when exists (select * from inserted) then 1 else 0 end)
| (select case when exists (select * from deleted ) then 2 else 0 end))
;
-- 21 <- Binary bit values
-- 00 -> No Rows Modified
-- 01 -> INSERT -- INSERT and UPDATE have the 1 bit set
-- 11 -> UPDATE <
-- 10 -> DELETE -- DELETE and UPDATE have the 2 bit set
raiserror(N'#Action = %d', 10, 1, #Action) with nowait
;
if (#Action = 0) raiserror(N'No Data Modified.', 10, 1) with nowait
;
-- do things for INSERT only
if (#Action = 1) raiserror(N'Only for INSERT.', 10, 1) with nowait
;
-- do things for UPDATE only
if (#Action = 3) raiserror(N'Only for UPDATE.', 10, 1) with nowait
;
-- do things for DELETE only
if (#Action = 2) raiserror(N'Only for DELETE.', 10, 1) with nowait
;
-- do things for INSERT or UPDATE
if (#Action & 1 = 1) raiserror(N'For INSERT or UPDATE.', 10, 1) with nowait
;
-- do things for UPDATE or DELETE
if (#Action & 2 = 2) raiserror(N'For UPDATE or DELETE.', 10, 1) with nowait
;
-- do things for INSERT or DELETE (unlikely)
if (#Action in (1,2)) raiserror(N'For INSERT or DELETE.', 10, 1) with nowait
-- if already "return" on #Action = 0, then use #Action < 3 for INSERT or DELETE
;
GO
set nocount on;
raiserror(N'
INSERT 0...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 0 object_id from sys.objects;
raiserror(N'
INSERT 3...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 3 object_id from sys.objects;
raiserror(N'
UPDATE 0...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t where asdf <> asdf;
raiserror(N'
UPDATE 3...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t;
raiserror(N'
DELETE 0...', 10, 1) with nowait;
delete t from dbo.TrigAction t where asdf < 0;
raiserror(N'
DELETE 3...', 10, 1) with nowait;
delete t from dbo.TrigAction t;
GO
drop table dbo.TrigAction
;
GO
Quick solution MySQL
By the way: I'm using MySQL PDO.
(1) In an auto increment table just get the highest value (my column name = id) from the incremented column once every script run first:
$select = "
SELECT MAX(id) AS maxid
FROM [tablename]
LIMIT 1
";
(2) Run the MySQL query as you normaly would, and cast the result to integer, e.g.:
$iMaxId = (int) $result[0]->maxid;
(3) After the "INSERT INTO ... ON DUPLICATE KEY UPDATE" query get the last inserted id your prefered way, e.g.:
$iLastInsertId = (int) $db->lastInsertId();
(4) Compare and react: If the lastInsertId is higher than the highest in the table, it's probably an INSERT, right? And vice versa.
if ($iLastInsertId > $iMaxObjektId) {
// IT'S AN INSERT
}
else {
// IT'S AN UPDATE
}
I know it's quick and maybe dirty. And it's an old post. But, hey, I was searching for a solution a for long time, and maybe somebody finds my way somewhat useful anyway. All the best!
In first scenario I supposed that your table have IDENTITY column
CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
FOR INSERT, UPDATE, DELETE
AS
IF ##ROWCOUNT = 0 return
SET NOCOUNT ON;
DECLARE #action nvarchar(10)
SELECT #action = CASE WHEN COUNT(i.Id) > COUNT(d.Id) THEN 'inserted'
WHEN COUNT(i.Id) < COUNT(d.Id) THEN 'deleted' ELSE 'updated' END
FROM inserted i FULL JOIN deleted d ON i.Id = d.Id
In second scenario don't need to use IDENTITTY column
CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
FOR INSERT, UPDATE, DELETE
AS
IF ##ROWCOUNT = 0 return
SET NOCOUNT ON;
DECLARE #action nvarchar(10),
#insCount int = (SELECT COUNT(*) FROM inserted),
#delCount int = (SELECT COUNT(*) FROM deleted)
SELECT #action = CASE WHEN #insCount > #delCount THEN 'inserted'
WHEN #insCount < #delCount THEN 'deleted' ELSE 'updated' END
DECLARE #INSERTEDCOUNT INT,
#DELETEDCOUNT INT
SELECT #INSERTEDCOUNT = COUNT([YourColumnName]) FROM inserted
SELECT #DELETEDCOUNT = COUNT([YourColumnName]) FROM deleted
IF its updation
#INSERTEDCOUNT = 1
#DELETEDCOUNT = 1
if its insertion
#INSERTEDCOUNT = 1
#DELETEDCOUNT = 0
I've used those exists (select * from inserted/deleted) queries for a long time, but it's still not enough for empty CRUD operations (when there're no records in inserted and deleted tables). So after researching this topic a little bit I've found more precise solution:
declare
#columns_count int = ?? -- number of columns in the table,
#columns_updated_count int = 0
-- this is kind of long way to get number of actually updated columns
-- from columns_updated() mask, it's better to create helper table
-- or at least function in the real system
with cte_columns as (
select #columns_count as n
union all
select n - 1 from cte_columns where n > 1
), cte_bitmasks as (
select
n,
(n - 1) / 8 + 1 as byte_number,
power(2, (n - 1) % 8) as bit_mask
from cte_columns
)
select
#columns_updated_count = count(*)
from cte_bitmasks as c
where
convert(varbinary(1), substring(#columns_updated_mask, c.byte_number, 1)) & c.bit_mask > 0
-- actual check
if exists (select * from inserted)
if exists (select * from deleted)
select #operation = 'U'
else
select #operation = 'I'
else if exists (select * from deleted)
select #operation = 'D'
else if #columns_updated_count = #columns_count
select #operation = 'I'
else if #columns_updated_count > 0
select #operation = 'U'
else
select #operation = 'D'
It's also possible to use columns_updated() & power(2, column_id - 1) > 0 to see if the column is updated, but it's not safe for tables with big number of columns. I've used a bit complex way of calculating (see helpful article below).
Also, this approach will still incorrectly classifies some updates as inserts (if every column in the table is affected by update), and probably it will classifies inserts where there only default values are inserted as deletes, but those are king of rare operations (at lease in my system they are).
Besides that, I don't know how to improve this solution at the moment.
COLUMNS_UPDATED() for audit triggers by Piotr Rodak
Dealing with very large bitmasks by Adam Machanic
declare #result as smallint
declare #delete as smallint = 2
declare #insert as smallint = 4
declare #update as smallint = 6
SELECT #result = POWER(2*(SELECT count(*) from deleted),1) + POWER(2*(SELECT
count(*) from inserted),2)
if (#result & #update = #update)
BEGIN
print 'update'
SET #result=0
END
if (#result & #delete = #delete)
print 'delete'
if (#result & #insert = #insert)
print 'insert'
i do this:
select isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)
1 -> insert
2 -> delete
3 -> update
set #i = isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)
--select #i
declare #action varchar(1) = case #i when 1 then 'I' when 2 then 'D' when 3 then 'U' end
--select #action
select #action c1,* from inserted t1 where #i in (1,3) union all
select #action c1,* from deleted t1 where #i in (2)

Resources