SQL Trigger after insert update - sql-server

What is wrong with this code.
If i type like this
Declare tmp as CURSOR FOR
Select i.ID from Inserted
OPEN tmp
Or if i type
Declare tmp as CURSOR FOR
Select i.ID from Deleted
OPEN tmp
Works like a charm but
Is there any way i can write something like this
if #operation <> 3
set #tmp = 'SELECT i.id FROM inserted i '
else
set #tmp =' SELECT i.id FROM deleted i '
DECLARE tmpUpit CURSOR FOR
#tmp
OPEN tmpUpit
Edit :
CREATE TRIGGER [dbo].[ax_Triger] ON [dbo].[extraTable]
FOR INSERT, UPDATE, DELETE AS
SET NOCOUNT ON;
--Capture the Operation (Inserted, Deleted Or Updated)
DECLARE #operation int
DECLARE #Count AS INT
SET #operation = 1
SELECT #Count = COUNT(*)
FROM DELETED
IF #Count > 0
BEGIN
SET #operation = 3
SELECT #Count = COUNT(*)
FROM INSERTED
IF #Count > 0
SET #operation = 2
END
DECLARE tmpUpit CURSOR FOR
SELECT i.id FROM inserted i
OPEN tmpUpit
FETCH NEXT FROM tmpUpit
into #ID WHILE ##fetch_status = 0
begin If Not exists
(SELECT * FROM mytable
where (Operation=3 OR (Operation=1 AND ID=#ID)) AND Status = 0 AND Tablename ='extraTable')
begin INSERT INTO
mytable ([Field1], [Field2],
[ID], [Tablename], [Operation], [Time12], [Status])
VALUES (#Field1, #Field2, #ID, 'extraTable', #operation,GETDATE(),0)
DELETE FROM mytable
WHERE [Field1]=#Field1 And [Field2]=#Field2 And [ID]=#ID And [Tablename]='extraTable'
AND [Operation] = 4 AND [Status] = 0
End
FETCH NEXT FROM tmpUpit into #ID
End CLOSE tmpUpit DEALLOCATE tmpUpit end
i need to insert the value from one table to another depending about the status Inserted/updated/deleted

This is completely untested since the table structures posted did not match the posted trigger code. This should at least demonstrate how you can rethink about this as set based logic instead of row by agonizing row.
CREATE TRIGGER [dbo].[Trigger212] ON [dbo].[Towns]
FOR INSERT, UPDATE, DELETE AS
BEGIN
SET NOCOUNT ON;
DECLARE #operation int
DECLARE #Variable1 nvarchar(8) = 'Woof'
DECLARE #Variable2 nvarchar(4) = 'Foof'
--Capture the Operation (Inserted, Deleted Or Updated)
IF EXISTS(SELECT * FROM inserted) AND NOT EXISTS (SELECT * FROM deleted)
SET #operation = 1 --Insert
ELSE
IF EXISTS(SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted)
SET #operation = 2 --update
ELSE
SET #operation = 3 -- DELETE
INSERT Requests
(
Field1
, Field2
, ID
, TableName
, Operation
, TimeU
, Status
)
SELECT 'Woof'
, 'Foof'
, i.ID
, 'Towns'
, #operation
, GETDATE()
, 0
FROM inserted i
LEFT JOIN Requests r on r.ID = i.ID
AND r.Operation = 3
OR (r.Operation = 1 and r.ID = i.ID)
AND r.Status = 0
AND r.TableName = 'Towns'
WHERE r.ID IS NULL
DELETE r
FROM Requests r
JOIN inserted i on i.Field1 = r.Field1
AND i.Field2 = r.Field2
AND i.ID = r.ID
AND i.Operation <> #operation
WHERE r.TableName = 'Towns'
AND r.Status = 0
END
In general I think triggers should be avoided but they have their place. When triggers are appropriate I am generally not a big fan of doing all three operations. Over time it gets really messy because invariably you need to do different logic for the different operations. Splitting them into three triggers makes this eventuality a lot less painful for maintenance.

Related

Adding a duplicate number

I'm currently experiencing the following problem.
If you have a look at the below test case:
declare #Count int
, #id int = 777
declare #table table
( id int identity primary key
, JCid int
, line int
, udf float )
insert into #table (jcid,line,udf)
values
(777,1,1),
(777,2,2.1),
(777,3,2.2),
(777,4,2),
(777,5,3)
select
#Count = count(left(L.udf,1))
from #table L
where L.jcid = #id
group by left(L.udf,1)
having count(left(L.udf,1))>1
select #Count
When I run this, I get the desired results of 3, however upon developing the below trigger, I can't get the count to work out correctly:
create trigger kv_trg_JobLineNumberUpdate_AW on _btblJCTxLines
after insert, update
as
declare #LineNum float
, #OldLine float
, #id int
, #Count int
, #Err nvarchar(500)
set #Err = '--------------------------';
set #Err = #Err + #Err + CHAR(10);
set #Err = #Err + CHAR(10);
set #Err = #Err + 'You are not allowed to change this Line Number!';
select
#LineNum = iLineID
, #OldLine = isnull(ufJCTxCMLineNumber,0)
, #id = iJCMasterID
from inserted
select
#Count = count(left(L.ufJCTxCMLineNumber,1))
from _btblJCTxLines L
join inserted i on left(L.ufJCTxCMLineNumber,1) = left(i.ufJCTxCMLineNumber,1)
where L.iJCMasterID = #id
group by left(L.ufJCTxCMLineNumber,1)
having count(left(L.ufJCTxCMLineNumber,1))>1
begin
if #OldLine = 0
begin
if #Count >= 2
begin
update _btblJCTxLines
set ufJCTxCMLineNumber = cast(#LineNum as varchar)+'.'+cast(#Count as varchar)
from _btblJCTxLines L
join inserted on L.idJCTxLines = inserted.idJCTxLines
end
else
begin
update _btblJCTxLines
set ufJCTxCMLineNumber = #LineNum
from _btblJCTxLines L
join inserted on L.idJCTxLines = inserted.idJCTxLines
end
end
else
begin
select
#OldLine = deleted.ufJCTxCMLineNumber
, #LineNum = inserted.ufJCTxCMLineNumber
from inserted, deleted
if (#OldLine <> #LineNum)
begin
raiserror(#Err, 16, 1)
rollback tran
return;
end
end
end
go
The ufJCTxCMLineNumber field is the duplicate number I'm looking for.
This triggers main purpose is to ensure that the ufJCTxCMLineNumber field never has duplicates.
What happens is, a user inserts a new line, when they add a new line above any current line, I want the ufJCTxCMLineNumber field to be updated to 3.1 depending on how many duplicates there is.
How would I go about getting the correct count?
Follow this link for Sample Data.

SqlServer Trigger to add multiple rows

I have the following trigger:
ALTER TRIGGER .[dbo].[trgAfterInsertComment]
ON .[dbo].[Comment]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #Id int;
declare #LoanId int;
declare #CopyId int;
declare #CustomerId int;
declare #Comment nvarchar(255);
--DECLARE cur CURSOR FOR
select #Id = Id from inserted
select #LoanId = LoanId from inserted
--select #CopyId = CopyId from deleted
--select #CustomerId = CustomerId from deleted
select #Comment = Comment from inserted
-- OPEN cur
--FETCH NEXT FROM cur INTO #Id, #ISBN, #Purchase_Date
--WHILE ##FETCH_STATUS = 0 BEGIN
-- your business logic
Declare #Title nvarchar(255);
select #Title = (Select Title from Book where ISBN = (select ISBN from copy where Id = (select CopyId from Loan where Id = #LoanId)))
select #CustomerId = (Select CustomerId from Loan where Id = #LoanId)
select #CopyId = (Select CopyId from Loan where Id = #LoanId)
insert into Activity("Heading", "Date")
values(Concat('New Comment added - Id: ', #Id, ' Title: ', #Title, ' Copy Id: ', #CopyId, ' Customer Id: ', #CustomerId, ' Comment: ', #Comment), GETDATE())
--FETCH NEXT FROM cur INTO #Id, #ISBN, #Purchase_Date
--END
--CLOSE cur
--DEALLOCATE cur
end
As you can see I have commented out a cursor that I was using to handle multiple inserts. Could someone tell me how I can handle multiple inserts without the cursor, as after reading around I see that using a cursor is a bad idea?
With the above trigger, if I try to insert multiple lines like this:
USE [Library]
GO
INSERT INTO [dbo].[Comment]
([LoanId]
,[Comment])
VALUES
(47, 'test'),
(48, 'test'),
(50, 'test')
GO
Only the first row is inserted into my Activity table. Thanks for any help
You need to shift it to be set based, using variables and a loop will cause you issues. Can't test the below, but something like:
INSERT INTO Activity
(
Heading ,
[Date]
)
SELECT CONCAT('New Comment added - Id: ', I.id, ' Title: ', COALESCE(B.Title,''), ' Copy Id: ', COALESCE(L.CopyID,''), ' Customer Id: ', COALESCE(L.CustomerID,'')) ,
GETDATE()
FROM inserted AS I
LEFT JOIN Loan AS L ON I.loanId = L.loanId
LEFT JOIN Copy AS C ON C.Id = L.CopyId
LEFT JOIN Book AS B ON B.ISBN = C.ISBN;
Do this querying inserted table directly.
insert into [dbo].[Comment] (LoanId, Comment)
select LoanId, Comment from inserted
You can change the select query to more complex to achieve the result using query only.

Trigger to handle multiple row inserts and updates

I am using the following trigger to track inserts and updates on multiple tables and log it in a log table.
CREATE TRIGGER tr_TestTable1]
ON [TestTable_1]
AFTER INSERT, UPDATE
AS
DECLARE #keyid int, #tn nvarchar(50), #recEditMode nvarchar(50), #trstat nvarchar(50)
BEGIN
SET NOCOUNT ON;
SET #tn = 'TestTable_1'
IF EXISTS(SELECT 1 FROM INSERTED)
BEGIN
SET #recEditMode = (Select REC_EDIT_MODE FROM inserted)
SET #trstat = 'PENDING'
SET #keyid = (Select prkeyId FROM inserted)
IF (#recEditMode = 'MANUAL')
BEGIN
IF NOT EXISTS (SELECT * FROM [logTable_1] WHERE SourceKeyId = #keyid AND TrStatus = 'PENDING' AND SourceTableName = #tn)
BEGIN
INSERT INTO [logTable_1](SourceKeyId,SourceTableName,TrStatus)
VALUES (#keyid, #tn, #trstat)
END
END
END
END
This works fine on single row insert and single row update. I am unable to optimize this code to handle multi row inserts and updates. Looking for some help in handling this.
Thanks.
I modified the trigger as below and it seems to be working fine now...
CREATE TRIGGER tr_TestTable1]
ON [TestTable_1]
AFTER INSERT, UPDATE
AS
DECLARE #keyid int, #tn nvarchar(50), #trstat nvarchar(50)
BEGIN
IF ##ROWCOUNT = 0
RETURN
SET NOCOUNT ON;
IF EXISTS(SELECT * FROM INSERTED)
BEGIN
SET #tn = 'TestTable_1'
SET #trstat = 'PENDING'
BEGIN
INSERT INTO LogTable_1 (SourceKeyId, SourceTableName, TrStatus)
SELECT I.prKeyId, #tn, #trStat FROM INSERTED AS I
WHERE (I.REC_EDIT_MODE = 'MANUAL' AND NOT EXISTS(SELECT * FROM LogTable_1 WHERE SourceKeyId = I.prKeyId AND SourceTableName = #tn AND TrStatus = 'PENDING'))
END
END
END

select query returns empty in sp but when run it alone, it is not empty. Why?

I have a stored procedure that I write to Table and read table. I write with no problem but when I want to read it returns empty. but it is not empty when I select query and run it returns data. Why it can be.
Here is my codes. I give fulltext index Dump and TempTable to tag,title and body columns.
IF LEFT(#splitdata,1) = '#'
BEGIN
SET #splitdata = (SELECT REPLACE(#splitdata,'#',''))
INSERT INTO [WebTR].[dbo].[TempTable]
SELECT p.*
FROM [WebTR].[dbo].[Dump] AS p
INNER JOIN containstable([WebTR].[dbo].[Dump], tags, #splitdata) AS k
ON p.dumpID = k.[key]
end
SET #replacedLast += #replaced2
FETCH NEXT FROM TableA_cursor INTO #row
I insert temptable first then
IF EXISTS(SELECT * FROM WebTR.dbo.TempTable)
BEGIN
SELECT #replacedLast AS withtag
select dumpId,title,source,tags,creationdate,status,body,createdBy,max(rank) as rank,'olsanaaa' AS sinir
from
((SELECT p.*, k.rank
FROM WebTR.dbo.TempTable AS p
INNER JOIN containstable(WebTR.dbo.TempTable, title,'"*cunku*"' ) AS k
ON p.dumpID = k.[key]
)
union
(
SELECT p.*, k.rank
FROM WebTR.dbo.TempTable AS p
INNER JOIN containstable(WebTR.dbo.TempTable, body, '"*cunku*"') AS k
ON p.dumpID = k.[key]
))y group by dumpId,title,source,tags,creationdate,status,body,createdBy
order by rank DESC
END
as you can see in that if block when I select only select query it returns data but when execute stored procedure it returns empty even it enters the if block
here is he full sp:
USE [WebTR]
GO
/****** Object: StoredProcedure [dbo].[search] Script Date: 10.6.2015 16:19:25 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[search]
#param1 varchar(250)
AS
BEGIN
declare #searchString varchar(250)
set #searchString = LTrim(RTrim(#param1))
TRUNCATE TABLE [WebTR].[dbo].[TempTable]
--SELECT ROW_NUMBER() OVER(ORDER BY #param1 ASC) AS row , * INTO #temp1 from WebTR.dbo.fnsplitstring(#searchString ,'')
SELECT ROW_NUMBER() OVER(ORDER BY CAST(SUBSTRING(splitdata, 0, 2) AS CHAR(1)) desc) AS row,* INTO #params from WebTR.dbo.fnsplitstring(#searchString ,'')
SET NOCOUNT ON
DECLARE #row INT
DECLARE #splitdata VARCHAR(50)
DECLARE #replaced1 VARCHAR(500)
DECLARE #replaced2 VARCHAR(500)
DECLARE #replacedLast VARCHAR(500)
DECLARE #last VARCHAR(500)
DECLARE TableA_cursor CURSOR FOR SELECT row FROM #params
SET #last = (SELECT COUNT(*) FROM #params)
SET #replacedLast = ''
OPEN TableA_cursor
FETCH NEXT FROM TableA_cursor INTO #row
WHILE ##FETCH_STATUS = 0
BEGIN
SET #splitdata = (SELECT splitdata FROM #params WHERE row=#row)
IF LEFT(#splitdata,1) = '#'
BEGIN
SET #splitdata = (SELECT REPLACE(#splitdata,'#',''))
BEGIN TRANSACTION
INSERT INTO [WebTR].[dbo].[TempTable]
SELECT p.*
FROM [WebTR].[dbo].[Dump] AS p
INNER JOIN containstable([WebTR].[dbo].[Dump], tags, #splitdata) AS k
ON p.dumpID = k.[key]
COMMIT TRANSACTION
end
ELSE
begin
IF LEFT(#splitdata,1)='-'
BEGIN
IF RIGHT(#replacedLast,4) = 'AND '
BEGIN
SET #replaced1 =('NOT ')
END
ELSE
BEGIN
SET
#replaced1 =('NOT ')
end
SET #replaced2= #replaced1 + (SELECT REPLACE (#splitdata, '-', '"*'))
SET #replaced2= #replaced2 + '*" ' + 'AND '
END
ELSE
BEGIN
SET #replaced2 =('"*')
SET #replaced2 = #replaced2 + (SELECT #splitdata + '*" AND ')
END
SET #replacedLast += #replaced2
END
FETCH NEXT FROM TableA_cursor INTO #row
IF ##FETCH_STATUS !=0
BEGIN
IF RIGHT(#replacedLast,4)='AND '
BEGIN
SET #replacedLast =LEFT(#replacedLast,(LEN(#replacedLast)-3))
END
END
END
CLOSE TableA_cursor
DEALLOCATE TableA_cursor
IF EXISTS(SELECT * FROM WebTR.dbo.TempTable)
BEGIN
SELECT #replacedLast AS withtag
select dumpId,title,source,tags,creationdate,status,body,createdBy,max(rank) as rank,'olsanaaa' AS sinir
from
((SELECT p.*, k.rank
FROM WebTR.dbo.TempTable AS p
INNER JOIN containstable(WebTR.dbo.TempTable, title,'"*cunku*"' ) AS k
ON p.dumpID = k.[key]
)
union
(
SELECT p.*, k.rank
FROM WebTR.dbo.TempTable AS p
INNER JOIN containstable(WebTR.dbo.TempTable, body, '"*cunku*"') AS k
ON p.dumpID = k.[key]
))y group by dumpId,title,source,tags,creationdate,status,body,createdBy
order by rank DESC
END
ELSE
BEGIN
select * into #temp1
from
((SELECT p.*, k.rank
FROM [WebTR].[dbo].[Dump] AS p
INNER JOIN containstable([WebTR].[dbo].[Dump], title, #replacedLast) AS k
ON p.dumpID = k.[key]
)
union
(
SELECT p.*, k.rank
FROM [WebTR].[dbo].[Dump] AS p
INNER JOIN containstable([WebTR].[dbo].[Dump], body, #replacedLast) AS k
ON p.dumpID = k.[key]
))x
select dumpId,title,source,tags,creationdate,status,body,createdBy,max(rank) as rank
from #temp1 with (NOLOCK)
group by dumpId,title,source,tags,creationdate,status,body,createdBy
order by rank DESC
DROP TABLE #temp1
end
END
CLOSE TableA_cursor
DEALLOCATE TableA_cursor
did you checked this part ? Because your cursor is closing before some actions.
I have this misbehaviour in SQL Server 2008 too. If you insert and retrieve too fast with fulltext index your query won't result in the new queries.
Maybe you need a manual population of your fulltext index.
See example based on AdventureWorks
ALTER FULLTEXT INDEX ON HumanResources.JobCandidate START UPDATE POPULATION;
GO
https://technet.microsoft.com/en-us/library/ms142575.aspx
Hopefully the Population update will fix your issue.
Best regards,
Ionic

Insert update delete trigger

Dear all I´m having trouble with my trigger.
Am I doing this at all right, right now it only works for Insert. I think I´m pretty close tho please help me if you have the time. I´m trying to store all the inserts, updates and deletes into the table customers_changelog via trigger. There is something wrong with the code I cant delete or update customers I can only insert new ones. Please help my I have been spending plenty of hours on this and just cant get this to work! :)
create table customers (
customerid int identity primary key,
name varchar(100) not null,
address varchar(100)
)
go
create table customers_changelog (
customerid int,
name varchar(100) not null,
address varchar(100),
change_user varchar(32),
change_time datetime,
change_action char(1) default 'I',
check (change_action = 'I' or change_action = 'D')
)
go
CREATE TRIGGER log_changes
ON customers
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
--
-- Check if this is an INSERT, UPDATE or DELETE Action.
--
DECLARE #customerid1 as int;
DEClARE #name1 as varchar(32);
DECLARE #address1 as varchar(100);
DECLARE #change_action1 as char(1);
DECLARE #change_time1 as datetime;
DECLARE #change_user1 as varchar(32);
select #customerid1 = c.customerid, #name1 = c.name, #address1 = c.address
from customers c, inserted i
where c.customerid = i.customerid
SET #change_time1 = CURRENT_TIMESTAMP;
SET #change_user1 = CURRENT_USER;
INSERT INTO customers_changelog(customerid,name,address,change_action,change_time,change_user)
VALUES(#customerid1,#name1,#address1,'I',#change_time1,#change_user1)
IF EXISTS(SELECT * FROM DELETED)
BEGIN
IF EXISTS(SELECT * FROM INSERTED)
INSERT INTO customers_changelog VALUES(#customerid1,#name1,#address1,'U',#change_time1,#change_user1)
ELSE
INSERT INTO customers_changelog VALUES(#customerid1,#name1,#address1,'D',#change_time1,#change_user1)
END
ELSE
IF NOT EXISTS(SELECT * FROM INSERTED) RETURN;
END
Assuming MS-SQL from syntax - So couple issues here:
1. Need to specify column lists in the "update" and "delete" inserts because the column order in the table doesn't match your inserts.
2. Can't use "inserted" data for delete insert
ALTER TRIGGER [dbo].[log_changes] ON [dbo].[customers] AFTER INSERT, UPDATE, DELETE AS
BEGIN
SET NOCOUNT ON;
DECLARE #customerid1 as int;
DEClARE #name1 as varchar(32);
DECLARE #address1 as varchar(100);
DECLARE #change_action1 as char(1);
DECLARE #change_time1 as datetime;
DECLARE #change_user1 as varchar(32);
select #customerid1 = c.customerid, #name1 = c.name, #address1 = c.address
from customers c, inserted i
where c.customerid = i.customerid
SET #change_time1 = CURRENT_TIMESTAMP;
SET #change_user1 = CURRENT_USER;
IF EXISTS(SELECT * FROM DELETED)
BEGIN
IF EXISTS(SELECT * FROM INSERTED)
INSERT INTO customers_changelog(customerid,name,address,change_action,change_time,change_user)
VALUES(#customerid1,#name1,#address1,'U',#change_time1,#change_user1)
ELSE
BEGIN
select #customerid1 = d.customerid, #name1 = d.name, #address1 = d.address
from deleted d
INSERT INTO customers_changelog(customerid,name,address,change_action,change_time,change_user)
VALUES(#customerid1,#name1,#address1,'D',#change_time1,#change_user1)
END
END
ELSE
BEGIN
IF NOT EXISTS(SELECT * FROM INSERTED) RETURN;
INSERT INTO customers_changelog(customerid,name,address,change_action,change_time,change_user)
VALUES(#customerid1,#name1,#address1,'I',#change_time1,#change_user1)
END
END

Resources