How to create trigger to check if table changed - sql

I'm beginner and i trying to create trigger to check if table changed then i track the changed and insert it into another table
i created table called history and this is my code
create table history
(
ProjectNo INT ,
UserName NVARCHAR(50),
ModifiedDate date,
Budget_Old int,
Budget_New int,
)
and created this trigger
CREATE TRIGGER t1 on history
on project AFTER UPDATE
AS BEGIN
IF UPDATE(Project.Pnumber,Project.Budget)
INSERT INTO dbo.history (ProjectNo , Username,ModifiedDate,Budget_Old,Budget_New)
SELECT
d.ProjectNo, suser_name() ,GETDATE(),d.Budget,i.budget
FROM
Deleted d , inserted i
where d.projectno = i.projectno
END
i think my if statment is wrong but what i should do to make my query run right
to insert this values in history table ? plz help me and sorry for bad English

Triggers have access to two logical tables that have an identical structure to the table they are defined on which us Project as I assume.
INSERTED, which is the new data to go into the table
DELETED, which is the old data the is in the table
So You can get the old values in this way:
CREATE TRIGGER t1
ON dbo.Project AFTER UPDATE
AS
INSERT INTO dbo.history (ProjectNo , Username)
SELECT d.ProjectNo , d.Username
FROM DELETED d
If you need to just have one record for specific project in the table history, then you would use inner join based on the projectNo and update the history table accordingly.

ITS WORKS BUDDY ENJOY!!!!!!!!!!!
CREATE TRIGGER tRIGGERNAME1
BEFORE UPDATE on history
FOR EACH ROW
BEGIN
INSERT INTO dbo.history (ProjectNo ,Budget_Old,Budget_New)
VALUES(:OLD.ProjectNo,:OLD.Budget_Old,:NEW.Budget_New);
END;

Related

I want to make a table audit/shadow table only when the email column of my table is updated

when i update one row (email) the trigger sends all of the data to the shadow table I only want the one row that was updated what am i doing wrong in mt trigger code below?
CREATE TRIGGER AspNetUsersEmail_trigger
ON AspNetUsers
AFTER INSERT, UPDATE
AS
IF ( UPDATE (Email) )
BEGIN
INSERT INTO [dbo].[AspNetUserEmailAudit]([UserId],[UserName],[Email],[NormalizedEmail],[FirstName],[LastName])
SELECT Id,[UserName],[Email],[NormalizedEmail],[FirstName],[LastName] FROM AspNetUsers
END;
UPDATE [Elearn2].[dbo].[AspNetUsers]
SET Email = 'isaac#gmail.com'
WHERE [Id] = 'A1785377-E3BA-483A-8600-024CA5885951'
you should use inserted table:
CREATE TRIGGER AspNetUsersEmail_trigger
ON AspNetUsers
AFTER INSERT, UPDATE
AS
IF ( UPDATE (Email) )
BEGIN
INSERT INTO [dbo].[AspNetUserEmailAudit]([UserId],[UserName],[Email],[NormalizedEmail],[FirstName],[LastName])
SELECT Id,[UserName],[Email],[NormalizedEmail],[FirstName],[LastName]
FROM INSERTED
END;
read more about these special tables here
In MS SQL you have to select the data from the table inserted.
The tables deleted and inserted exists in triggers and contains the deleted and updated / inserted rows.

Creating A Trigger When Insert Is Already Done

I created a SQL trigger where I want to update a column("Documents") in my table "Article". I have another table which is "Files" where a FileId is stored. So now i want that FileId in my column "Documents".
I created this trigger:
CREATE TRIGGER [InsertDocumentId]
ON [dbo].[Files]
FOR UPDATE
AS
INSERT INTO [Article]
(Documents)
SELECT
FileId FROM Files LEFT JOIN Article t on Files.ArticleId = t.ArticleId;
GO
But this isn't working...
Hope you guys can help me out.
If I understand correctly, you want to insert table B after insert table A. If that's correct, you can try to use this block of query:
CREATE TRIGGER [InsertDocumentId] ON [dbo].[Files]
FOR INSERT
AS
INSERT INTO [Article] (Documents)
SELECT FileId FROM INSERTED f;
GO

Insert multiple records into table for each user in another table in SQL Server

I want to create notification application in node js and I just created a database with these three tables in SQL Server:
tbluser
user_id
user_name
tbluser_notification
user_id
noti_id
read
tblnotification
noti_id
noti_title
noti_mesg
noti_create
noti_sender_id
My question is: whenever I insert a notification into tblnotification, I want to insert a record for each user into the tbluser_notification.
Create after insert trigger
CREATE TRIGGER [dbo].[trgtblnotificationInsert]
ON [dbo].[tblnotification]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO tbluser_notification (user_id, noti_id, notificationread)
SELECT tbluser.user_id, inserted.noti_id, 0
FROM tbluser
CROSS JOIN inserted
END
Please note: I have changed the column name 'read' to 'notificationread' as read is reserved word.

Insert multiple rows into a table with a trigger on insert into another table

I am attempting to create a T-SQL trigger that will essentially insert x number of rows into a third table based upon the data being inserted into the original table and data contained in a second table; however, I'm getting all sorts of errors in the select portions of the insert statement.
If I comment out this portion [qmgmt].[dbo].[skillColumns].[columnID] in (select columnID from [qmgmt].[dbo].[skillColumns]), IntelliSense gets rid of all the red lines.
Table designs:
Users table - contains user info
skillColumns table - list of all columns possible, filtered on the productGroupID of the user
Skills table - contains the data per user, one row for every columnID in skillColumns
CREATE TRIGGER tr_Users_INSERT
ON [qmgmt].[dbo].[Users]
AFTER INSERT
AS
BEGIN
INSERT into [qmgmt].[dbo].[Skills]([userID], [displayName], [columnID])
Select [iTable].[userID],
[iTable].[displayName],
[cID] in (select [columnID] as [cID] from [qmgmt].[dbo].[skillColumns])
From inserted as [iTable] inner join
[qmgmt].[dbo].[skillColumns] on
[iTable].[productGroupID] = [qmgmt].[dbo].[skillColumns].[groupID]
END
GO
Is what I'm looking to accomplish even possible with a trigger? Can multiple rows be inserted into a table with the in keyword?
UPDATE:
After using the answer provided by J0e3gan, I was able to create a trigger in the opposite direction:
CREATE TRIGGER tr_skillColumns_INSERT_Users
ON [qmgmt].[dbo].[skillColumns]
AFTER INSERT
AS
BEGIN
INTO [qmgmt].[dbo].[Skills]([userID], [displayName], [columnID])
Select [qmgmt].[dbo].[Users].[userID],
[qmgmt].[dbo].[Users].[displayName],
[iTable].[columnID]
From inserted as [iTable] inner Join
[qmgmt].[dbo].[Users] on
[iTable].[groupID] = [qmgmt].[dbo].[Users].[productGroupID]
Where
[qmgmt].[dbo].[Users].[userID] in (select [userID] from [qmgmt].[dbo].[Users])
END
GO
Yes, this can be done with an AFTER trigger.
The column list is not the correct place for the IN criterion that you are trying to use, which is why it is underlined in red.
Try adding the IN criterion to the JOIN criteria instead:
CREATE TRIGGER tr_Users_INSERT
ON [qmgmt].[dbo].[Users]
AFTER INSERT
AS
BEGIN
INSERT into [qmgmt].[dbo].[Skills]([userID], [displayName], [columnID])
Select [iTable].[userID],
[iTable].[displayName],
[qmgmt].[dbo].[skillColumns].[columnID]
From inserted as [iTable] inner join
[qmgmt].[dbo].[skillColumns] on
[iTable].[productGroupID] = [qmgmt].[dbo].[skillColumns].[groupID] and
[qmgmt].[dbo].[skillColumns].[columnID] in (select columnID from [qmgmt].[dbo].[skillColumns])
END
GO
Alternatively add it to a WHERE clause:
CREATE TRIGGER tr_Users_INSERT
ON [qmgmt].[dbo].[Users]
AFTER INSERT
AS
BEGIN
INSERT into [qmgmt].[dbo].[Skills]([userID], [displayName], [columnID])
Select [iTable].[userID],
[iTable].[displayName],
[qmgmt].[dbo].[skillColumns].[columnID]
From inserted as [iTable] inner join
[qmgmt].[dbo].[skillColumns] on
[iTable].[productGroupID] = [qmgmt].[dbo].[skillColumns].[groupID]
Where
[qmgmt].[dbo].[skillColumns].[columnID] in (select columnID from [qmgmt].[dbo].[skillColumns])
END
GO

Creating a trigger to insert records from a table to another one. Triggered column of table 'A' is inserted as null in table 'B' [duplicate]

This question already has an answer here:
Create a trigger to insert records from a table to another one. Get inserted values in a trigger
(1 answer)
Closed 9 years ago.
I have two tables tbl_PurchaseDetails and tbl_ItemDetails. I need to insert some records into tbl_ItemDetails from tbl_PurchaseDetails, right after it is inserted in tbl_PurchaseDetails. tbl_PurchaseDetails has auto generated custom field PurchaseID.
Code for auto generation of PurchaseID is:-
*This trigger works perfectly*
CREATE FUNCTION CreatePurchaseID (#id INT)
RETURNSvarchar(10)
AS
BEGIN
RETURN 'P' + CONVERT(VARCHAR(10), #id)
END
CREATE TRIGGER trigger_PurchaseID ON tbl_PurchaseDetails
FOR INSERT AS
UPDATE
tbl_PurchaseDetails
SET
tbl_PurchaseDetails.PurchaseID = dbo.CreatePurchaseID(tbl_PurchaseDetails.ID)
FROM
tbl_PurchaseDetails
INNER JOIN
INSERTED on tbl_PurchaseDetails.ID= INSERTED.ID
I have written the following code for trigger to insert into tbl_ItemDetails:-
CREATE TRIGGER trigger_UpdateItemDetails ON tbl_PurchaseDetails
FOR INSERT AS
DECLARE #PurchaseID VARCHAR(20)
DECLARE #Quantity INT
DECLARE #WarehouseID VARCHAR(20)
SELECT #PurchaseID=(PurchaseID) FROM INSERTED
SELECT #Quantity=(ItemQuantity) FROM INSERTED
SELECT #WarehouseID=(WarehouseID) FROM INSERTED
INSERT INTO
tbl_ItemDetails
(PurchaseID,Quantity,WarehouseID)
VALUES
(
#PurchaseID,#Quantity,#WarehouseID
)
**And now when i insert into tbl_PurchaseDetails the records are added to tbl_PurchaseDetails and tbl_ItemDetails successfully. The problem here is, the PurchaseID is inserted as null in tbl_ItemDetails. It is inserted as expected in tbl_PurchaseDetails though.
From my comments, here's what I'd have:
CREATE TABLE PurchaseDetails ( --Why have a tbl_ prefix on every table?
ID int IDENTITY(1,1) not null,
PurchaseID as 'P' + CONVERT(VARCHAR(10), ID),
--Other columns
)
I then wouldn't need your first trigger and function. I could then re-write the second trigger as:
CREATE TRIGGER trigger_UpdateItemDetails ON PurchaseDetails
FOR INSERT AS
INSERT INTO ItemDetails(PurchaseID,Quantity,WarehouseID)
SELECT PurchaseID,ItemQuantity,WarehouseID
FROM inserted
which deals with inserted potentially containing multiple rows.
Re: my comment in the first snippet about tbl_ prefixes - I'd argue that it's not just adding redundant information, it's adding potential for confusion. The only two types of objects that can appear, ambiguously, in the same position within a query are tables and views. Any other type of object (function, stored procedure, column, parameter, etc) can always be distinguished by syntax at the point of usage.
And, as much as possible, you shouldn't want or need to distinguish between tables and views. Being able to completely change a table, but then provide a view that has the same layout as the original table, and the same name, and then not having to change any other code is a great virtue in SQL. But it feels kind of silly when you have to name your view tbl_ABC because you were using tbl_ as a prefix for tables.