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
Related
I am writing a procedure in SQL Server to insert or update records.
The update part of the code is working fine but when I am executing it for inserting, duplicate entries are inserted into the table.
I created the primary key to avoid this error but after creating that I am not able to insert any single record.
Here is the code :
Alter Procedure test_case
#id int,
#name nvarchar(20)
AS
If exists (Select t_id from testing2 where t_id = #id)
begin
update testing2
set t_id = #id, t_name = #name
where t_id = #id
end
else
begin
insert into testing2 (t_id, t_name, last_date, hard)
select
#id, #name, convert(date, getdate()), 'null'
from test
end
On executing it is showing 2 rows affected
You do not require test table in the select query
insert into testing2 (t_id, t_name, last_date, hard)
select
#id as t_id, #name as t_name, convert(date, getdate()) as last_date, 'null' as hard
is enough
I like to break functionality into smaller parts because it helps me to manage code better.
Maybe this is not a good example since it is pretty simple but I will write it anyway.
Create Procedure Testing2_InsertData (
#id int,
#name nvarchar(20)
) As
Set NoCount On
Insert Into testing2
(t_id, t_name, last_date, hard)
Values
( #id, #name, GetDate(), null )
Go
Create Procedure Testing2_UpdateData (
#id int,
#name nvarchar(20)
) As
Set NoCount On
Update testing2 Set
t_name = #name --, maybe last_date = GetDate()
Where ( t_id = #id )
Go
Create Procedure Testing2_SaveData (
#id int,
#name nvarchar(20)
) As
Set NoCount On
If ( Exists( Select t_id From testing2 Where ( t_id = #id ) ) )
Exec Testing2_UpdateData #id, #name
Else
Exec Testing2_InsertData #id, #name
Go
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
USE [mydatabase]
GO
/****** Object: Trigger [dbo].[trgAfterInsert] Script Date: 14.11.2014 2:30:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trgAfterInsert] ON [dbo].[MYTABLE]
FOR INSERT
AS
declare #ID int;
declare #DATE date;
declare #WHEN smalldatetime;
declare #WHO NVARCHAR(50);
declare #WHAT NVARCHAR(max);
declare #AUDIT_ACTION varchar(100);
select #ID = i.ID from inserted i;
select #DATE = i.DATE from inserted i;
select #WHEN = i.WHEN from inserted i;
select #WHO = i.WHO from inserted i;
select #WHAT = i.WHAT from inserted i;
UPDATE MYTABLE
SET WHEN = GETDATE(),
WHO = USER_NAME(USER_ID())
FROM dbo.MYTABLE
INNER JOIN inserted ON MYTABLE.ID = inserted.ID
insert into AUDIT_LOG
(DATE,WHEN,WHO,WHAT,USER,AUDIT_ACTION,AUDIT_TIMESTAMP)
values
(#DATE,#WHEN,#WHO,#WHAT,USER_NAME(USER_ID()),'NEW ENTRY',GETDATE());
When run,'when' and 'who' dont get inserted into AUDIT_LOG.
What I am trying to do here is to first update the table and then log
altogether.
What am I doing wrong?
I Think The SQL Editor dealing with the Column 'WHEN' as if it is a reserved keyword, so try to put it between brackets like this [WHEN]
I am trying to create an 'instead of insert trigger' that will not let the name 'john' insert anything into a table. My problem is that even if i change the name to something else, the query is successful but the values arent added.
Any help would be appreciated, thanks in advance.
CREATE TRIGGER InsteadOfTrigger
ON Question4
INSTEAD OF INSERT
AS
Declare #name varchar(50)
Declare #question varchar(50)
Declare #Answer char
Set #name = 'John'
IF (select Username from inserted) = #name
BEGIN
RAISERROR ('You have not paid up your fee', 10,1)
ROLLBACK TRANSACTION
END
ELSE
BEGIN
INSERT INTO question4
values (#name, #question, #Answer)
END
Ok So I have removed your BEGIN and END statements between your IF ELSE statement and wrapped the trigger logic within a BEGIN END
As mentioned in the comments below you dont need the ROLLBACK TRANSACTION
Also you will need to populate #question and #Answer for those to be of any use.
CREATE TRIGGER InsteadOfTrigger
ON Question4
INSTEAD OF INSERT
AS
BEGIN
Declare #name varchar(50)
Declare #question varchar(50)
Declare #Answer char
Set #name = 'John'
IF (select Username from inserted) = #name
RAISERROR ('You have not paid up your fee', 10,1)
--ROLLBACK TRANSACTION
ELSE
INSERT INTO question4
values (#name, #question, #Answer)
END
Hmm, I notice you have declared, but not actually set a value for your variables in your else statement this may have caused SQL to not insert what you expected.
Strangely enough I'm required to do the same in an assignment at the moment, Here's my solution:
CREATE TRIGGER instead_of_insert
ON Question4
INSTEAD OF INSERT AS
Declare #Username varchar(25)
Declare #Question varchar(6)
Declare #Answer char(1)
Set #Username ='John'
IF (Select UserName from inserted) = #UserName
Begin
RAISERROR ('You have not paid up your fee', 10,1)
End
Else
Begin
Set #Username = (Select UserName from inserted)
Set #Question = (Select Question_ID from inserted)
Set #Answer = (Select Answer from inserted)
Insert into User_Responses
Values
(#username, #Question, #Answer)
End
I have two tables User & User Log . User log table basically logs all the changes(insert/update/delete) made to user table.
I have a trigger on User table which is as below:
ALTER TRIGGER [dbo].[TRG_UserLog]
ON [dbo].[Users]
FOR INSERT,UPDATE,DELETE
AS
-- Declare variables here
DECLARE #UserName VARCHAR(50)
DECLARE #FirstName VARCHAR(50)
DECLARE #LastName VARCHAR(50)
DECLARE #Email VARCHAR(50)
DECLARE #RoleID INT
DECLARE #UpdatedBy VARCHAR(50)
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
IF ##ROWCOUNT = 0
BEGIN
RETURN
END
IF EXISTS(SELECT * FROM INSERTED)
--INSERTED / UPDATED
BEGIN
SET #UserName = ( SELECT UserName FROM INSERTED)
SET #FirstName = ( SELECT FirstName FROM INSERTED)
SET #LastName = ( SELECT LastName FROM INSERTED)
SET #Email = ( SELECT Email FROM INSERTED)
SET #RoleID = ( SELECT RoleID FROM INSERTED)
SET #UpdatedBy = ( SELECT ModifiedBy FROM INSERTED)
INSERT INTO UserLog(UserName,FirstName,LastName,Email,RoleID,[DateTime],UpdatedBy)
VALUES (#UserName,#FirstName,#LastName,#Email,#RoleID,GETDATE(),#UpdatedBy)
END
ELSE
-- DELETED
BEGIN
SET #UserName = ( SELECT UserName FROM DELETED)
SET #FirstName = ( SELECT FirstName FROM DELETED)
SET #LastName = ( SELECT LastName FROM DELETED)
SET #Email = ( SELECT Email FROM DELETED)
SET #RoleID = ( SELECT RoleID FROM DELETED)
SET #UpdatedBy = ( SELECT ModifiedBy FROM DELETED)
INSERT INTO UserLog(UserName,FirstName,LastName,Email,RoleID,[DateTime],UpdatedBy)
VALUES (#UserName,#FirstName,#LastName,#Email,#RoleID,GETDATE(),#UpdatedBy)
END
END
The above triigger is not inserting data in userlog table when insert/update or delete is made to user table. Is there anything wrong with the code?
You should not be setting variables from INSERTED and DELETED. These "tables" could potentially hold more than 1 row in them and using set is going to lose data. Do this instead (on both the INSERT and DELETE blocks):
INSERT INTO UserLog(UserName, FirstName, LastName, Email, RoleID, [DateTime], UpdatedBy)
SELECT UserName, FirstName, LastName, Email, RoleID, getdate(), ModifiedBy
FROM INSERTED
If you make that change, you don't even need the IF/ELSE blocks, since it'll only INSERT/DELETE based on whether or not there are rows in those tables.
Also, the check on ##ROWCOUNT is unnecessary. You should be able to remove that completely.
This will always be true:
SET NOCOUNT ON; -- this sets ##ROWCOUNT to 0
IF ##ROWCOUNT = 0
BEGIN
RETURN
END
because calling SET NOCOUNT ON; affects ##ROWCOUNT, and since no rows are affected by that statement, it's set to 0. So the rest of the code never runs. At the very least, you would run that code before SET NOCOUNT ON; (or store ##ROWCOUNT in a variable for later use), but as indicated by the other answer, it's completely unnecessary anyway.