If statement in AFTER DELETE trigger not working - sql

I have a trigger which I would like to do something if a certain condition is met.
If a user causes the system to remove a row from a security table, and that row happens to fit particular criteria, I want to run a stored proc. The problem that I'm running into is that the trigger behaves as though the if statement's criteria is not met. I know that the criteria is being met, because I tried piping the variable in question into a table, and the value I came up with was correct.
If I remove the IF statement, the procedure runs (though indiscriminately...it runs as expected, regardless of the value of the personorgroup field in the deleted table, which is not what I want it to do.)
Here is the trigger:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter TRIGGER dbo.SecurityPersonRemoval
ON dbo.[security]
AFTER delete
AS
BEGIN
SET NOCOUNT ON;
declare #person int
declare #thing int
select #person = personorgroup from deleted
select #thing = thing from deleted
if #person = '37671721'
exec docsadm.ethicalwall #thing
END
GO
Ideas?

Your statement probably fails because "deleted" can contain multiple records. Assigning the value of the select to a scalar will only return the first personID and the rest will be ignored. If you must call docsamd.ehticalwall for each person deleted, you could use a cursor:
declare #personId int,
#thingId int,
#fetchStatus int
declare myDeletedPeople cursor for select personorgroup, thing from deleted readonly
open myDeletedPeople
fetch myDeletedPeople into #personId, #thingId
select #fetchStatus = ##FETCH_STATUS
while (#fetchStatus=0)
begin
if(#personId = '37671721')
begin
exec docsadm.ethicalwall #thingId
end
fetch myDeletedPeople into #personId, #thingId
select #fetchStatus = ##FETCH_STATUS
end
close myDeletedPeople
deallocate myDeletedPeople

Related

T-SQL TRIGGER return 1 more "Rows Affected" Than expected when INSERT data

I have a table with a secondary key. Before inserting, I want to check if this secondary key exists in another table as primary key.
To do this I've create a trigger in T-SQL on this table. Here it is:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trg_tb_repair_order_before]
ON [dbo].[tb_repair_order]
INSTEAD OF INSERT
AS
BEGIN
DECLARE #or_code NVARCHAR(50)
DECLARE #or_designation NVARCHAR(300)
DECLARE #or_comment NVARCHAR(3000)
DECLARE #code_customer NVARCHAR(50)
DECLARE cur_tb_repair_order_before CURSOR FOR
SELECT or_code, or_designation, or_comment, code_customer
FROM inserted
OPEN cur_tb_repair_order_before
FETCH NEXT FROM cur_tb_repair_order_before INTO #or_code, #or_designation, #or_comment, #code_customer
WHILE ##FETCH_STATUS = 0
BEGIN
IF ((SELECT Count(*) FROM tb_customer WHERE code = #code_customer) > 0)
BEGIN
IF ((SELECT COUNT(*) FROM inserted) > 0)
BEGIN
INSERT INTO tb_repair_order (or_code, or_designation, or_comment, code_customer)
VALUES (#or_code, #or_designation, #or_comment, #code_customer)
END
END
FETCH NEXT FROM cur_tb_repair_order_before INTO #or_code, #or_designation, #or_comment, #code_customer
END
CLOSE cur_tb_repair_order_before
DEALLOCATE cur_tb_repair_order_before
END
Everything is good, this trigger works perfectly.
The problem is the number of rows inserted
Here is result for wrong secondary key
As we can see, SQL returns "1 rows affected" but nothing is inserted into the table ...
Here is result for good secondary key
And here SQL returns "2 rows affected".
If someone can explain how I can return the correct result because in my C# code the ExecuteNonQuery function returns not the expected result and it's bad practice to continue with this.
Thanks in advance

I can't catch interested ID from inserted and use it in exec of stored procedure

I can't execute a procedure in my trigger with a parameter from the inserted pseudo table.
ALTER TRIGGER [dbo].[Restauracja]
ON [dbo].[RezerwacjaPozycje]
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
DECLARE #ID INT;
SELECT IdReservation = #ID
FROM INSERTED
EXEC SumOrderPositions #ID;
END
If I change #id to f.e. 9. it correctly updates what I want for IdReservation number 9.
If you are inserting only one row, you can simply do the assignment in the correct order:
BEGIN
DECLARE #ID int;
SELECT #ID = IdReservation
FROM INSERTED;
EXEC SumOrderPositions #ID;
END;
However, this is a bug waiting to happen. Instead, you may want to use a cursor, loop through the rows in inserted using some other mechanism, or check that there is only one row in inserted. I'm not sure the exactly logic that you want.

Multiple rows are getting inserted into a table (which is not desired) as part of a stored procedure

Update: This still remain a mystery. Checked the calling code and we did not find anything that would make the SP run in a loop.
For now we have split the SP into two which seems to have arrested the issue although not able to reason how that has helped out.
Database: MS SQL Server.
I have a SP which performs few operations - i.e inserts a row into 3 tables based on certain status as part of that SP being called.
It is getting called from our web application based on a user action.
We have cases, few times a day where the same row gets inserted multiple times (sometime more than 50+) with the same values in each row except that if you look at the datetime when the row was inserted there is a difference of few milliseconds. So it is unlikely that the user is initiating that action.
This SP is not running in a Transaction or with any locks however it is getting called probably concurrently multiple times as we have many concurrent users on the web application invoking this action.
My question is what is causing the same row to insert so many times? If concurrent execution of SP was an issue where we are updating same row then it is understood one may overwrite the other. However in this case each user calls in the SP with different parameters.
I have put the said operation in a Transaction to monitor the behavior however was looking to find out what exactly causes these kind of multiple inserts with same value just a few milliseconds apart?
USE [ABC]
GO
/****** Object: StoredProcedure [dbo].[AddProcessAdmittedDocUploadScrutinyWithLog] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[AddProcessAdmittedDocUploadScrutinyWithLog]
(
--Insert using bulk
#stdfrm_id int,
#course_id int,
#stdfrm_scrt_apprvby int,
#stdfrm_scrt_apprvcomment varchar(max),
#sRemainingDocs varchar(max),
#DTProcessAdmittedDocUploadScrutiny AS dbo.MyDTProcessAdmittedDocUploadScrutiny READONLY
)
AS
BEGIN
DECLARE #result char
SET #result='N'
--New
declare #AuditCount int=0;
select #AuditCount=count(scrtaudit_id) from tbl_ProcessAdmittedScrutinyAuditLog
where stdfrm_id=#stdfrm_id and stdfrm_scrt_apprvby=#stdfrm_scrt_apprvby
and stdfrm_scrt_apprvcomment=#stdfrm_scrt_apprvcomment and convert(date,stdfrm_scrt_apprvon,103)=convert(date,getdate(),103)
--Checked extra conditon to avoid repeatation
if(#AuditCount=0)
BEGIN
--Call Insert
BEGIN TRY
/*Remaining Documents----------*/
DECLARE #sdtdoc_id Table (n int primary key identity(1,1), id int)
if(#sRemainingDocs is not null)
begin
--INSERT INTO #sdtdoc_id (id) SELECT Name from splitstring(#sRemainingDocs)
INSERT INTO #sdtdoc_id (id) SELECT [Value] from dbo.FN_ListToTable(#sRemainingDocs,',')
end
Declare #isRemaining int=0;
SELECT #isRemaining=Count(*) FROM #sdtdoc_id
/*Calculate stdfrm_scrt_apprvstatus*/
Declare #stdfrm_scrt_apprvstatus char(1)='A';--Approved
Declare #TotalDescripancies int;
select #TotalDescripancies=count(doc_id) from #DTProcessAdmittedDocUploadScrutiny where doc_id_scrtyn='Y'
if(#isRemaining>0)
begin
set #stdfrm_scrt_apprvstatus='H';--Discrepancies Found
end
else if exists (select count(doc_id) from #DTProcessAdmittedDocUploadScrutiny where doc_id_scrtyn='Y')
begin
if(#TotalDescripancies>0)
begin
set #stdfrm_scrt_apprvstatus='H';--Discrepancies Found
end
end
/* Check if Discrepancies Found first time then assign to Checker o.w assign to direct college like grievance*/
if(#stdfrm_scrt_apprvstatus='H')
begin
declare #countAuditLog int=0;
select #countAuditLog=count(stdfrm_id) from tbl_ProcessAdmittedScrutinyAuditLog where stdfrm_id =#stdfrm_id
if (#countAuditLog=0)
begin
set #stdfrm_scrt_apprvstatus='G'--'E';--Discrepancies Found set Edit request assign to Checker
end
--else if (#countAuditLog=1)
-- begin
--set #stdfrm_scrt_apprvstatus='G';--Discrepancies Found set Grievance assign to college
-- end
end
/*----------------------*/
/*Update status in original table-----*/
Update tbl_ProcessAdmitted set stdfrm_scrt_apprvstatus=#stdfrm_scrt_apprvstatus
,stdfrm_scrt_apprvon=getdate(),stdfrm_scrt_apprvby=#stdfrm_scrt_apprvby
,stdfrm_scrt_apprvcomment=#stdfrm_scrt_apprvcomment
where stdfrm_id =#stdfrm_id
/*Add in Main Student Log-----------*/
/********* The row here gets inserted multiple times *******************/
INSERT into tbl_ProcessAdmittedScrutinyAuditLog
(stdfrm_id, stdfrm_scrt_apprvstatus, stdfrm_scrt_apprvon, stdfrm_scrt_apprvby, stdfrm_scrt_apprvcomment )
values
(#stdfrm_id, #stdfrm_scrt_apprvstatus, getdate(), #stdfrm_scrt_apprvby, #stdfrm_scrt_apprvcomment)
DECLARE #scrtaudit_id int =##identity
/*Completed -------------------------*/
DELETE FROM tbl_ProcessAdmittedDocUploadScrutiny WHERE stdfrm_id =#stdfrm_id
SET NOCOUNT ON;
/********* The row here gets inserted multiple times *******************/
INSERT tbl_ProcessAdmittedDocUploadScrutiny
(stdfrm_id, course_id, doc_id, doc_id_scrtyn, doc_id_scrtrmrk, doc_id_comment)
SELECT #stdfrm_id, #course_id, doc_id, doc_id_scrtyn, doc_id_scrtrmrk, doc_id_comment
FROM #DTProcessAdmittedDocUploadScrutiny;
/*Scrutiny Document Log -------------------------*/
/********* The row here gets inserted multiple times *******************/
INSERT tbl_ProcessAdmittedDocUploadScrutinyAuditLog
(scrtaudit_id,stdfrm_id, course_id, doc_id, doc_id_scrtyn, doc_id_scrtrmrk, doc_id_comment)
SELECT #scrtaudit_id,#stdfrm_id, #course_id, doc_id, doc_id_scrtyn, doc_id_scrtrmrk, doc_id_comment
FROM #DTProcessAdmittedDocUploadScrutiny;
/*Remaining Documents Insert into table*/
DELETE FROM tbl_ProcessAdmittedDocUploadScrutinyRemiaing WHERE stdfrm_id =#stdfrm_id
DECLARE #Id int,#doc_id int
WHILE (SELECT Count(*) FROM #sdtdoc_id) > 0
BEGIN
Select Top 1 #Id = n,#doc_id=id From #sdtdoc_id
--Do some processing here
insert into tbl_ProcessAdmittedDocUploadScrutinyRemiaing(stdfrm_id, doc_id )
values (#stdfrm_id,#doc_id)
insert into tbl_ProcessAdmittedDocUploadScrutinyRemiaingAuditLog
(scrtaudit_id, stdfrm_id, doc_id )
values (#scrtaudit_id,#stdfrm_id,#doc_id)
DELETE FROM #sdtdoc_id WHERE n = #Id
END --Begin end While
/*End Remaining Documents-----------*/
SET #result=#stdfrm_scrt_apprvstatus
END TRY
BEGIN CATCH
SET #result='N'
insert into tbl_ErrorSql( ErrorMessage, stdfrm_id)
values(coalesce(Error_Message(),ERROR_LINE()),#stdfrm_id)
END CATCH;
--End of Call Insert
END
SELECT #result
END

Run a Script Each time a table is modified

I have created a batch script which prints information on the table into a label and saves it into pdf. At the moment, I am giving the script a number, which is the ItemCode and it prints out the rest of the information in the table.
Well now I'm going much further, my goal is to run the script each time the table is modified, or a new row is added or even if a single field is modified. When this happens it would check which row has been modified and It would run the script with the ItemCode which has been modified.
Been looking for something similar to this but couldn't find anything precise enough, so any help would be nice!
The code below is part of a trigger I am using. It writes old values and new values into a special table to track all important changes. The updated_idx is send with the SQL command to tell, what user is doing it.:
USE [Demo] -- database
GO
/****** Object: Trigger [dbo].[update_Address] Script Date: 26.07.2018 11:16:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[update_Address] ON [dbo].[Address] for UPDATE AS
DECLARE #fieldname varchar(128) = '- empty -'
DECLARE #newValue varchar(2048) = '- empty -'
DECLARE #oldValue varchar(2048)= '- empty -'
DECLARE #Updated int = datediff(s,'01/01/1970',SYSUTCDATETIME())
DECLARE #Updated_IDX int = -1
DECLARE #ID int = -1
DECLARE db_cursor CURSOR FOR SELECT Address_id, Updated_IDX FROM inserted
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #ID, #Updated_IDX -- this takes the current id
WHILE ##FETCH_STATUS = 0
BEGIN
SET NOCOUNT ON
If UPDATE([ZipCode])
BEGIN
SELECT #OldValue=b.ZipCode, #NewValue=a.ZipCode FROM inserted a, deleted b
IF #NewValue <> #OldValue
BEGIN
INSERT INTO TransactionLog ([ID],[TableName],[Type],[FieldName],[newValue],[oldValue],[Updated],[Updated_IDX]) values (#ID,'Address','U','ZipCode',#newValue,#oldValue,#Updated,#Updated_IDX);
END
END
If UPDATE([City])
BEGIN
SELECT #OldValue=b.City, #NewValue=a.City FROM inserted a, deleted b
IF #NewValue <> #OldValue
BEGIN
INSERT INTO TransactionLog ([ID],[TableName],[Type],[FieldName],[newValue],[oldValue],[Updated],[Updated_IDX]) values (#ID,'Address','U','City',#newValue,#oldValue,#Updated,#Updated_IDX);
END
END
FETCH NEXT FROM db_cursor INTO #ID, #Updated_IDX
End
CLOSE db_cursor
DEALLOCATE db_cursor

Cursor - Declare Select-Statement executed multiple times?

I've got a question regarding cursor in t-sql.
when i do a cursor like that, it will end up in an endless loop.
drop table [dbo].[cursorcheck]
GO
CREATE TABLE [dbo].[cursorcheck](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Wert] [varchar](10) NOT NULL
) ON [PRIMARY]
GO
delete dbo.cursorcheck
GO
insert into dbo.cursorcheck
select 'Insert'
GO
DECLARE #vendor_id int, #vendor_name nvarchar(50);
DECLARE vendor_cursor CURSOR FOR
SELECT ID, wert
FROM dbo.cursorcheck
WHERE wert = 'insert';
OPEN vendor_cursor
FETCH NEXT FROM vendor_cursor
INTO #vendor_id, #vendor_name
WHILE ##FETCH_STATUS = 0
BEGIN
insert into dbo.cursorcheck
select 'Insert'
FETCH NEXT FROM vendor_cursor
INTO #vendor_id, #vendor_name
END
CLOSE vendor_cursor;
DEALLOCATE vendor_cursor;
I'm a bit confused about this behavior. Does that mean that the select script, the cursor was declared for, is executed multiple times? i got the same effect when i insert into that table from another transaction while debugging the cursor. the problem is solved when i use the "static" keyword for declaring the cursor. but i'm confused about the behavior of the cursor when i don't use the static keyword.
any explanation?
Regards,
Reto
The key is you try to read and insert the same table in loop (so it is like "a snake eating own tail"):
Cursor:
DECLARE vendor_cursor CURSOR FOR
SELECT ID, wert
FROM dbo.cursorcheck
WHERE wert = 'insert';
And loop:
WHILE ##FETCH_STATUS = 0
BEGIN
insert into dbo.cursorcheck
select 'Insert'
FETCH NEXT FROM vendor_cursor
INTO #vendor_id, #vendor_name
END
For second question: The problem is solved when i use the "static":
STATIC CURSOR
The complete result set of a static cursor is built in tempdb when the
cursor is opened. A static cursor always displays the result set as it
was when the cursor was opened.
and:
The cursor does not reflect any changes made in the database that
affect either the membership of the result set or changes to the
values in the columns of the rows that make up the result set. A
static cursor does not display new rows inserted in the database after
the cursor was opened, even if they match the search conditions of the
cursor SELECT statement