Values() constructor in SQL Server 2008 and triggers - sql

I have two tables Employee and Emp_Audit.
On table Employee, I have an AFTER INSERT trigger, which fires when I insert rows into Employee. The function of trigger is to insert the rows into the Emp_Audit table that have been inserted into Employee.
The trigger works fine when I explicitly use 'insert values' for each record to be inserted in Employee as
INSERT INTO Employee_Test VALUES ('Anees',1000);
INSERT INTO Employee_Test VALUES ('Rick',1200);
INSERT INTO Employee_Test VALUES ('John',1100);
INSERT INTO Employee_Test VALUES ('Stephen',1300);
INSERT INTO Employee_Test VALUES ('Maria',1400);
Trigger inserts all these rows inti Emp_Audit -------------GOOD
But when I use values constructor as
insert into dbo.Employee_Test
values ('Kritika', 25000),
('Ritu', 15000),
('Maduri', 7000),
('Dinkar', 7000);
Only the first row ('Kritika', 25000) gets inserted into Emp_Audit
The whole query is as follows:
CREATE TABLE Employee_Test
(
Emp_ID INT Identity,
Emp_name Varchar(100),
Emp_Sal Decimal (10,2)
)
CREATE TABLE Employee_Test_Audit
(
Emp_ID int,
Emp_name varchar(100),
Emp_Sal decimal (10,2),
Audit_Action varchar(100),
Audit_Timestamp datetime
)
-----------------------Trigger------------------------------------
CREATE TRIGGER trgInsertAfter ON [dbo].[Employee_Test]
FOR INSERT
AS
declare #empid int;
declare #empname varchar(100);
declare #empsal decimal(10,2);
declare #audit_action nvarchar(200);
select #empid = inserted.Emp_ID
FROM inserted;
select #empname = inserted.Emp_name
from inserted;
select #empsal = inserted.Emp_Sal
from inserted;
set #audit_action = 'Record Inserted after Insert Trigger Fired';
INSERT INTO Employee_Test_Audit
VALUES(#empid, #empname, #empsal, #audit_action, GETDATE());
GO
print('Insert trigger FIRED')
insert into dbo.Employee_Test
values ('Kritika', 25000),
('Ritu', 15000),
('Maduri', 7000),
('Dinkar', 7000);

Yep, what you want is:
CREATE TRIGGER trgInsertAfter ON [dbo].[Employee_Test]
FOR INSERT
AS
INSERT INTO Employee_Test_Audit (Emp_ID, Emp_name, Emp_Sal, Audit_Action, Audit_Timestamp)
SELECT Emp_ID,Emp_name,Emp_Sal,
'Record Inserted after Insert Trigger Fired',GETDATE()
from inserted;
Because inserted can contain multiple rows (or no rows), you have to treat it as a table. I've never seen any different behaviour, but there's no guarantee (in your version) that all of the variables would have been assigned values from the same row even.
Also, you really should get into the habit of supplying a column list to the INSERT.

Try this one -
CREATE TRIGGER dbo.trgInsertAfter
ON [dbo].[Employee_Test]
FOR INSERT
AS BEGIN
INSERT INTO dbo.Employee_Test_Audit(Emp_ID, Emp_name, Emp_Sal, ..., ...)
SELECT
i.Emp_ID
, i.Emp_name
, i.Emp_Sal
, 'Record Inserted after Insert Trigger Fired'
, GETDATE()
FROM INSERTED i
END

The reason of why only one record inserted is when you assign value to the variable using select then it don't provide any error and set the value to any arbitrary value in the column.
and also using that method only insert one record. So correct trigger code should be
CREATE TRIGGER trgInsertAfter ON [dbo].[Employee_Test]
FOR INSERT
AS
INSERT INTO Employee_Test_Audit
SELECT Emp_ID,Emp_name,Emp_Sal,
'Record Inserted after Insert Trigger Fired',GETDATE()
from inserted;

Related

Insert multiple rows using triggers using three tables

ALTER TRIGGER tr_ItemAccessInsert
ON [dbo].[tbl_InventoryGroup]
AFTER INSERT
AS
BEGIN
DECLARE #ID decimal(18,3), #InventoryID decimal(18,3)
SELECT #ID = [ItemID] FROM [dbo].[tbl_ItemMain]
SELECT #InventoryID = [GroupID] FROM inserted
INSERT INTO tbl_ItemInventoryAccess ([ItemID], [InventoryID], [Value])
VALUES (#ID, #InventoryID, '0.11')
END
this is my query for trigger
i have 10 item in tbl_itemmain so i want to insert all the 10 itemsid in the tbl_inventoryacess please help me with that
You would just use insert . . . select:
insert into tbl_ItemInventoryAccess ([ItemID], [InventoryID], [Value])
select i.??, i.GroupID, '0.11'
from inserted i;
It is unclear how ItemId is determined. I imagine that a table called tbl_ItemMain has more than one row. Perhaps you can just use i.ItemId.
if i am using like
Alter trigger tr_ItemAccessInsert
on [dbo].[tbl_InventoryGroup]
After insert
as begin
Declare #ID decimal(18,3),#InventoryID decimal(18,3)
select #InventoryID=[GroupID] from inserted
insert into tbl_ItemInventoryAccess([ItemID],[InventoryID],[Value]) values((select itemid from tbl_ItemMain) ,#inventoryid,'0')
end
getting an error subquery returned more than one value

how to create trigger on table after insert to add Row in Audit table

i want to Create a trigger on student table after insert to add Row in Student Audit table (Server User Name , Date, Note) where note will be “[username] Insert New Row with Key=[Key Value] in table student
create trigger t1 on Student
after insert
as
declare #x int
begin
insert into Audit
(ServerUserName, Date, Note)
select SUSER_SNAME(), getdate(),SUSER_SNAME()+'Insert New Row with Key'+#x+'in Student '
from Student t
end
go
how can i do this with #x that's i mean #x is equal key
Firstly, remove declare #x int line. You can't pass parameters to trigger. If you want to get inserted row, you can select it as inserted like this;
create trigger t1 on Student
after insert
as
begin
insert into Audit
(ServerUserName, Date, Note)
select SUSER_SNAME(), getdate(),SUSER_SNAME()+'Insert New Row with Key'+cast(t.Id as nvarchar(10))+'in Student '
from Student t where Id IN (select Id from inserted)
end
go

Not showing all records in After Insert trigger in SQL Server

I have a table table1 with some data:
create table table1
(
c1 varchar(20),
c2 varchar(20)
)
insert into table1 values('1','A')
insert into table1 values('2','B')
insert into table1 values('3','C')
insert into table1 values('4','D')
insert into table1 values('5','E')
insert into table1 values('6','F')
Now I created another table with the same structure called table2 :
create table table2
(
c1 varchar(20),
c2 varchar(20)
)
Then I created an After Insert trigger on table2 :
CREATE TRIGGER trgAfterInsert
ON [dbo].[table2]
FOR INSERT
AS
declare #c1 varchar(20);
declare #c2 varchar(20);
declare #audit_action varchar(100);
select #c1 = i.c1 from inserted i;
select #c2 = i.c2 from inserted i;
set #audit_action = 'Inserted Record -- After Insert Trigger.';
insert into table2_Audit(c1, c2, Audit_Action, Audit_Timestamp)
values(#c1, #c2, #audit_action, getdate());
PRINT 'AFTER INSERT trigger fired.'
GO
There is a problem that when i copy all data of table1 to tabe2 then in Audit table only one record show.It not show all inserted record.
I use this query for copy the record in table2:-
insert into table2(c1,c2) select c1,c2 from table1
Your trigger fires once for each insert statement issued against this table. not one for each row inserted in the table. Hence if more than one row is inserted you trigger definition should be able to handle more than one row.
Instead of using variables to capture values from inserted table and then insert them in table two, simply select from the inserted table and insert the data into Table2_audit.
A trigger to handle this would look something like........
CREATE TRIGGER trgAfterInsert ON [dbo].[table2]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
insert into table2_Audit (c1,c2,Audit_Action,Audit_Timestamp)
SELECT C1
, C2
, 'Inserted Record -- After Insert Trigger.'
, GETDATE()
FROM inserted ;
PRINT 'AFTER INSERT trigger fired.'
END
GO
Trigger is fired once per entire operation, change your code to:
CREATE TRIGGER trgAfterInsert ON [dbo].[table2]
FOR INSERT
AS
BEGIN
DECLARE #audit_action VARCHAR(100) = 'Inserted Record -- After Insert Trigger.';
INSERT INTO table2_Audit(c1,c2,Audit_Action,Audit_Timestamp)
SELECT i.c1, i.c2, #audit_action, GETDATE()
FROM inserted i;
END
Second don't use PRINT inside trigger;
More info
The behavior you are seeing is by design. DML triggers in SQL Server
are statement level triggers - they are fired once after
INSERT/UPDATE/DELETE/MERGE irrespective of how many rows are affected
by the DML statement. So you should write your logic in the trigger to
handle multiple rows in the inserted/deleted tables

Adding computed column in SQL

How to add computed column that calculates the sum of selected column.
this is what i've done but has an error..
ALTER TABLE dbo.tblEM_Reimbursement
ADD [Amount] AS (SELECT SUM(Total) FROM dbo.tblEM_ReimbursementEntry WHERE ReimbursementID = ReimbursementID)
it says
Msg 1046, Level 15, State 1, Line 2
Subqueries are not allowed in this context. Only scalar expressions are allowed.
Thanks in advance
You could use a user-defined function. Non tested code below.
CREATE FUNCTION dbo.Get_ReimbursementEntry (#ReimbursementID int)
RETURNS DECIMAL(10,2)
AS BEGIN
RETURN (SELECT SUM(Total) FROM dbo.tblEM_ReimbursementEntry WHERE ReimbursementID = ReimbursementID)
END
GO
ALTER TABLE dbo.tblEM_Reimbursement
ADD [Amount] AS (dbo.Get_ReimbursementEntry (ReimbursementID))
GO
but beware of the performance implications
You can use a Trigger. Trigger is a automated function written in PL/SQL whcih is called
after or before a particular event.
Read this tutorial for better understanding.
For SQL-Server read this and this.
Example:
CREATE TABLE Employee_Test
(
Emp_ID INT Identity,
Emp_name Varchar(100),
Emp_Sal Decimal (10,2)
)
INSERT INTO Employee_Test VALUES ('Anees',1000);
INSERT INTO Employee_Test VALUES ('Rick',1200);
INSERT INTO Employee_Test VALUES ('John',1100);
INSERT INTO Employee_Test VALUES ('Stephen',1300);
INSERT INTO Employee_Test VALUES ('Maria',1400);
Suppose you have another table:
CREATE TABLE Employee_Test_Audit
(
Emp_ID int,
Emp_name varchar(100),
Emp_Sal decimal (10,2),
Audit_Action varchar(100),
Audit_Timestamp datetime
)
This trigger is fired after an INSERT on the table. Let’s create the trigger as:
CREATE TRIGGER trgAfterInsert ON [dbo].[Employee_Test]
FOR INSERT
AS
declare #empid int;
declare #empname varchar(100);
declare #empsal decimal(10,2);
declare #audit_action varchar(100);
select #empid=i.Emp_ID from inserted i;
select #empname=i.Emp_Name from inserted i;
select #empsal=i.Emp_Sal from inserted i;
set #audit_action='Inserted Record -- After Insert Trigger.';
insert into Employee_Test_Audit
(Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp)
values(#empid,#empname,#empsal,#audit_action,getdate());
PRINT 'AFTER INSERT trigger fired.'
GO

Trigger insert old values- values that was updated

I need to create trigger in SQL Server 2008 that gone insert all values from one row in which some value was changed into Log table!
For example if i have table Employees that have column id, name , password, and i update this table and insert new value for column name, than i need to insert values that was in table Employees after update in table Log.
How I can do this? Thanks!
In your trigger, you have two pseudo-tables available, Inserted and Deleted, which contain those values.
In the case of an UPDATE, the Deleted table will contain the old values, while the Inserted table contains the new values.
So if you want to log the ID, OldValue, NewValue in your trigger, you'd need to write something like:
CREATE TRIGGER trgEmployeeUpdate
ON dbo.Employees AFTER UPDATE
AS
INSERT INTO dbo.LogTable(ID, OldValue, NewValue)
SELECT i.ID, d.Name, i.Name
FROM Inserted i
INNER JOIN Deleted d ON i.ID = d.ID
Basically, you join the Inserted and Deleted pseudo-tables, grab the ID (which is the same, I presume, in both cases), the old value from the Deleted table, the new value from the Inserted table, and you store everything in the LogTable
Here's an example update trigger:
create table Employees (id int identity, Name varchar(50), Password varchar(50))
create table Log (id int identity, EmployeeId int, LogDate datetime,
OldName varchar(50))
go
create trigger Employees_Trigger_Update on Employees
after update
as
insert into Log (EmployeeId, LogDate, OldName)
select id, getdate(), name
from deleted
go
insert into Employees (Name, Password) values ('Zaphoid', '6')
insert into Employees (Name, Password) values ('Beeblebox', '7')
update Employees set Name = 'Ford' where id = 1
select * from Log
This will print:
id EmployeeId LogDate OldName
1 1 2010-07-05 20:11:54.127 Zaphoid
In SQL Server 2008 you can use Change Data Capture for this. Details of how to set it up on a table are here http://msdn.microsoft.com/en-us/library/cc627369.aspx
createTRIGGER [dbo].[Table] ON [dbo].[table]
FOR UPDATE
AS
declare #empid int;
declare #empname varchar(100);
declare #empsal decimal(10,2);
declare #audit_action varchar(100);
declare #old_v varchar(100)
select #empid=i.Col_Name1 from inserted i;
select #empname=i.Col_Name2 from inserted i;
select #empsal=i.Col_Name2 from inserted i;
select #old_v=d.Col_Name from deleted d
if update(Col_Name1)
set #audit_action='Updated Record -- After Update Trigger.';
if update(Col_Name2)
set #audit_action='Updated Record -- After Update Trigger.';
insert into Employee_Test_Audit1(Col_name1,Col_name2,Col_name3,Col_name4,Col_name5,Col_name6(Old_values))
values(#empid,#empname,#empsal,#audit_action,getdate(),#old_v);
PRINT '----AFTER UPDATE Trigger fired-----.'
ALTER trigger ETU on Employee FOR UPDATE
AS
insert into Log (EmployeeId, LogDate, OldName)
select EmployeeId, getdate(), name
from deleted
go