I have a two database tables,that database tables connect with 1:1 relationship.Using a trigger i need to copy some coloumns data to Log table.(When New Insert or Update Happens)
Error (1) Invalid column name 'ItemTbl_ItemId'.
(2) Invalid column name 'Price'
(3)Column name or number of supplied values does not match table definition.
First Table has
Table Name - ItemTbl
ItemId, ItemName, ItemPrice,Comments, Brand_BrandId
Second Table
Table Name - ItemLog
ItemLogId, ItemTbl_ItemId,ItemName,ItemPrice,ModifiedDate
My Trigger
CREATE TRIGGER [dbo].[ItemHistoryTrigger]
ON [dbo].[ItemTbl]
FOR INSERT,UPDATE
AS
BEGIN
IF EXISTS(SELECT ItemId,ItemName,ItemPrice FROM INSERTED)
BEGIN
INSERT INTO [dbo].[ItemLog]
SELECT ItemTbl_ItemId,ItemName,ItemPrice FROM INSERTED;
END
END
I Just wanted to copy ItemName & ItemPrice from the first table to second table using trigger.
You have no column named ItemTbl_ItemId in the table you are creating the trigger (ItemTbl). Try this:
CREATE TRIGGER [dbo].[ItemHistoryTrigger]
ON [dbo].[ItemTbl]
FOR INSERT,UPDATE
AS
BEGIN
IF EXISTS(SELECT ItemId,ItemName,ItemPrice FROM INSERTED)
BEGIN
INSERT INTO [dbo].[ItemLog](ItemTbl_ItemId,ItemName,ItemPrice)
SELECT ItemId,ItemName,ItemPrice FROM INSERTED;
END
END
And this assumes that the ItemLog's columns ItemLogId and ModifiedDate are auto_incremented and have a default value respectively.
Related
I want to do audit trail on specific table like
what inserted,updated,deleted in table and all this logs are save in one table
I am using sql server 2012 .
Can any one please help me with how to achieve this?
Please note - Use of cursor is restricted
create an after trigger on that table and insert the records into the log table .
create trigger <trigger_name> after insert/update/delete/ on
table <orig table>
begin
insert into the log tables ('all the fields that you require');
end
Try using CDC (Change Data Capture). A very helpful tool which will help to manage the Audit Trail
Read the article from MSDN
This can be achieve using Triggers. Trigger will make your DML operations slower, if large Insert, Delete and Update operations are happening on your table. If it's small table you can create TRIGGER like below, to log the rows to another table based on the action occurred.
You can make use of Inserted and Deleted magic tables which hold the rows which are being Inserted and Deleted inside a trigger.
There is another alternate if you need more control over auditing using CDC (Change Data Capture).
CREATE TABLE TrailTable
(
Id INT,
Name VARCHAR(100)
);
CREATE TABLE TrailTableLog
(
Id INT,
Name VARCHAR(100),
Action CHAR(3)
);
Insert Into TrailTable VALUES (1,'Vi');
Insert Into TrailTable VALUES (2,'Vr');
Insert Into TrailTable VALUES (3,'An');
Insert Into TrailTable VALUES (4,'Ma');
CREATE TRIGGER dbo.TRG_IDU_TrailTable
ON dbo.TrailTable
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
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)
IF(#Action = 'I')
BEGIN
INSERT INTO TRG_IDU_TrailTable (Id, Name, Action)
SELECT Id, Name, 'I' FROM INSERTED;
END
IF(#Action = 'D')
BEGIN
INSERT INTO TRG_IDU_TrailTable (Id, Name, Action)
SELECT Id, Name, 'D' FROM DELETED;
END
IF(#Action = 'U')
BEGIN
INSERT INTO TRG_IDU_TrailTable (Id, Name, Action)
SELECT Id, Name, 'U-D' FROM INSERTED; -- Records Deleted to Update
INSERT INTO TRG_IDU_TrailTable (Id, Name, Action)
SELECT Id, Name, 'U-I' FROM INSERTED; --Records Inserted to Update
END
END
I am having two databases. When a new customer record is added into fDebtor table in database ABC, a new record should be appended in fDebtor table in database DEF as well.
Can some one help me to write a stored procedure for this?
there should be a validation to check whether the record is already exists in next table also
create trigger TRG_Insert_fDebtor on ABC.fDebtor
ON AFTER Insert
as
begin
SET NOCOUNT ON;
--- checking for the record exist in the DEF database
IF (select count(*) from DEF.fDebtor where exists(select * from inserted)) > 0
begin
----- insert record in your other database DEF
insert into DEF.fDebtor values ()
end
end
Try trigger like that made changes as you need that's just approach you can use.
How to create a trigger that updates a column in a table when a different column in the same table is updated.
So far I have done the following which works when any new data is created. Its able to copy data from "Purchase Requisition" to "PO_Number" however when data has been modified in "Purchase Requisition" , no changes is made to "PO_Number" and the value becomes NULL. Any kind help will be seriously appreciated.
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2]
AFTER INSERT
AS BEGIN
UPDATE dbo.TheCat2 SET PO_Number=(select Purchase_Requisition from inserted) where DocNo= (Select DocNo from inserted);
END
You need to add 'UPDATE' as well as insert to the trigger, otherwise it will only execute on new data, not updated data. Also added 'top 1' to the select statements from the inserted table to allow this to be 'safe' on batch updates, however it will only update 1 record.
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2]
AFTER INSERT, UPDATE
AS BEGIN
UPDATE dbo.TheCat2 SET PO_Number=(select top 1 Purchase_Requisition from inserted) where DocNo= (Select top 1 DocNo from inserted);
END
This might do what you want:
Your trigger is altering all rows in TheCat2. Presumably, you only want to alter the new ones:
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2] AFTER INSERT
AS
BEGIN
UPDATE tc
SET PO_Number = Purchase_Requisition
FROM dbo.TheCat2 tc JOIN
inserted i
on tc.DocNo = i.DocNo ;
END;
However, perhaps a computed column is sufficient for your purposes:
alter table add PO_Number as Purchase_Requisition;
all id columns has auto_increment
In my trigger:
ALTER trigger [dbo].[mytrig]
on [dbo].[requests]
after INSERT, UPDATE
as
begin
declare #MyId1 int
set #MyId1 = (select Id from inserted)
declare #MyId2 int
declare #MyId3 int
if (select column1 from inserted) = 1
begin
insert into [dbo].[contracts] select column1,column2,column3 .... from inserted
set #MyId2 = SCOPE_IDENTITY()
insert into [dbo].[History] select column1,column2,column3 .... from inserted
set #MyId3 = SCOPE_IDENTITY()
insert into [dbo].[contracts_depts](Id_Contract ,column5) select #MyId2,column6 from request_depts where Id_request=#MyId1
insert into [dbo].[History_depts] (Id_InHistory,column5) select #MyId3,column6 from request_depts where Id_request=#MyId1
end
end
#MyId1 returns value only after update but not after insert. Do I have to use scope_identity() or something ?
Your main issue is: you're assuming the triggers is called once per row - that is NOT the case!
The trigger is called once per statement, and if your statement affects multiple rows, the Inserted pseudo table will contain multiple rows - so your statement here
set #MyId1 = (select Id from inserted)
really isn't going to work - it will select one arbitrary row (out of however many there are).
You'll need to rewrite your trigger to take this fact into account! Assume that Inserted contains 100 rows - how do you want to deal with that? What are you trying to achieve? Triggers don't return values - they will record into an audit table, or update other rows, or something like that ....
I use this code to check if an element of the new entry is equal to an element of previously inserted data.
CREATE TRIGGER trig1 ON Table1
AFTER INSERT
AS
DECLARE trigcursor CURSOR FOR
SELECT Name FROM INSERTED
DECLARE #Name1 varchar(80)
OPEN trigcursor;
FETCH NEXT FROM trigcursor INTO #Name1
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS(SELECT * FROM Table1 WHERE Name= #Name1)
BEGIN
...
END
FETCH NEXT FROM trigcursor INTO #Name1
END
The problem is that for some reason the new entry exists also in the table Table1, not only in INSERTED. So the condition is always true. Can you help me why this happens? Is there a way to retrieve only the initial table without the new entry in it? Thanks!
Your trigger is AFTER INSERT on table Table1. It should be BEFORE INSERT if you expect not to find the record in the table.
Alternative: use INSTEAD OF INSERT trigger.
OR
Add another column that accepts null. Make it a number column so that it will be fast. Do not insert any value in it on the insert. Then, in the AFTER INSERT TRIGGER, the rows that have that column empty are the new ones. The ones that have the column filled with something are the old ones.
Then update empty columns with value.
eg: add column mark
After insert, look for the name:
SELECT * FROM Table1 WHERE Name= #Name1 and mark is not null
Once you found out whether or not it existed before, update everything with something:
update table1 set mark = 1 where mark is null