SQL Inserted table trigger - sql

If I run the following select statement inside an insert trigger, is it possible that it will return more than one result?:
DECLARE #variable char(1) = (SELECT ID FROM inserted)
If so, then what's the best to handle it?
Here is the problem that I am trying to solve: Every time when the new record is inserted into a table, I want to take the newly inserted ID and insert it into another table(if it doesn't exists).
Thank you!

Instead of
DECLARE #variable char(1) = (SELECT ID FROM inserted)
You can do something like following:
Declare #VarTempTbl as table (id int)
Insert into #VarTempTbl (id)
Select id from inserted
So that you can get those values for further processing

Now, I had created Two tables One for Master table and another for When any Insertion happens in that Master table, that entry has to inserted into the another table.
CREATE TABLE tblEmployee
(
Id int Primary Key,
Name nvarchar(30),
Gender nvarchar(10),
DepartmentId int
)
CREATE TABLE tblEmployee_New
(
Id int Primary Key,
Name nvarchar(30),
Gender nvarchar(10),
DepartmentId int
)
Trigger:
CREATE TRIGGER TR_EMPLOYEEDETAILS_AFTEROFINSERT
ON TBLEMPLOYEE
AFTER INSERT
AS
BEGIN
TRUNCATE TABLE tblEmployee_New
INSERT INTO TBLEMPLOYEE_NEW(ID, NAME, GENDER, DEPARTMENTID)
SELECT ID, NAME, GENDER, DEPARTMENTID
FROM INSERTED
END
Now Lets try to insert into record into a master table
Insert into tblEmployee values (1,'John', 'Male', 3)
Insert into tblEmployee values (2,'Mike', 'Male', 2)
It has automatically insert the newly inserted records into the another table.
If your want to remove the Previous records then add a drop Statement in that above Trigger.
Note: You can also use #Temp Table instead of creating a another table('tblEmployee_New')
Kinldy Share your comments

Related

how to move record from one database to another database

I have two database,where two table are same with all schema.
I want to move specific records of employees and employeesrates with all columns of both tables.
below is the query.
CREATE TABLE #emp
(
empID INT IDENTITY(1, 1) primary key ,
Firstname varchar(20)
);
CREATE TABLE #empRates
(
ID INT IDENTITY(1, 1) primary key ,
empid int, -- foreign key from #emp
rate decimal(10,3),
startdate datetime,
enddate datetime,
);
insert into #emp (firstname) values('First')
insert into #emp (firstname) values('Second')
insert into #emp (firstname) values('Third')
insert into #empRates(empid,rate,startdate,enddate) values(1,10,'2020/01/10','2020/01/20')
insert into #empRates(empid,rate,startdate,enddate) values(1,15,'2020/01/20','2020/01/30')
insert into #empRates(empid,rate,startdate,enddate) values(2,10,'2020/01/10','2020/01/20')
insert into #empRates(empid,rate,startdate,enddate) values(3,15,'2020/01/20','2020/01/30')
select * from #emp
select * from #empRates
drop table #emp
drop table #empRates
Here both database on same server. Database1 and Database2.
below my query which tried.
insert into database2..empRates(empid,rate,startdate,enddate) select empid,rate,startdate,enddate
from database1..empRates
Here my problem is both database have different records,so identity are different,so after insert other employee rates get displayed for another like mashed up.
I am using sql server 2012.
can you please provide the way.
You should take a look at this post --> How to turn IDENTITY_INSERT on and off using SQL Server 2008?
This way you can specify value for id column during insert, so rows on destination databases will keep IDs from origin.
Hope it helps!

Handling bulk insert on a table with multiple input sources in SQL

I am performing bulk insert on a table in sql server 2012, at the same time i am picking the last inserted row with max() function and inserting it into another table , how to perform this when my table is getting data from multiple sources because while performing insertion into secondary table there is time delay while insertions are still happening in primary table so next time max() will pick up last updated row and i will loose some rows which are not max() but still inserted into primary table meanwhile.
create table dbo.emp
(
id int primary key identity(1,1),
emp_id int,
name varchar(255),
address varchar(255)
)
create table dbo.empx
(
id int primary key,
emp_id int foreign key references dbo.emp(id),
)
declare #temp int ;
set #temp=1;
while #temp<1000
begin
insert into dbo.emp(emp_id,name,address)values (100+#temp,'Ename'+LTRIM(STR(#temp)),'123 Sample Address'+LTRIM(STR(#temp)));
set #temp=#temp+1;
insert into dbo.empx select max(dbo.emp.id),max(dbo.emp.emp_id) from dbo.emp
end
Use OUTPUT Clause...
CREATE TABLE #empx
(Id INT ,emp_id VARCHAR(50))
DECLARE #temp INT ;
SET #temp=1;
WHILE #temp<1000
BEGIN
INSERT INTO dbo.emp(emp_id,name,address)
OUTPUT INSERTED.Id,INSERTED.emp_id INTO #empx(Id,emp_id)
VALUES (100+#temp,'Ename'+LTRIM(STR(#temp)),'123 Sample Address'+LTRIM(STR(#temp)));
SET #temp=#temp+1;
END
INSERT INTO dbo.empx(Id,emp_id)
SELECT Id,emp_id FROM #empx
Or Use a trigger
CREATE TRIGGER EmpLog
ON dbo.emp
AFTER Insert
AS
BEGIN
SET NOCOUNT ON;
Insert into dbo.empx (id,emp_id) Select id,emp_id from inserted;
END
GO

Insert Records if not exist and then update with identity in one query

I have 2 tables.
create table Sales
(CustomerKey int
,ProductKey int
,CustomersProductsKey int
,SalesAmount decimal(19,4))
Create Table CustomersProducts
(CustomersProductsKey int IDENTITY(1,1),
CustomerKey int,
ProductKey int,
Attribute1 int,
Attribute2 varchar(max))
Currently when I add data to the sales table, I need to insert any new customerkey productkey combinations into the CustomersProducts table and then update the sales table with the resulting CustomersProductsKey identity value. This works.
Is there anyway that I can do this in one step? I don't know if a Merge can do an insert and update on the same if not matched step.
I also could be just looking at this the wrong way as well.
Thanks,
EDIT:
As you can imagine, the fact that I need to use a surrogate key is part of the design. It's needed for a BO report. Otherwise there would really be no need for CustomersProductsKey at all.
If add only one step to make it work,
I think we need create a another table and create trigger on the new table and CustomersProducts
create table CustomersSalesProducts
(CustomerKey int
,ProductKey int
,SalesAmount decimal(19,4)
,Attribute1 int
,Attribute2 varchar(max))
create trigger test1 on CustomersSalesProducts After Insert
as
begin
insert Sales select CustomerKey , ProductKey , 0, SalesAmount from inserted
insert CustomersProducts select CustomerKey , ProductKey , Attribute1, Attribute2 from inserted
end
go
create trigger test2 on CustomersProducts after insert
as
begin
Update Sales set CustomersProductsKey = inserted.CustomersProductsKey
from inserted , Sales
where inserted.CustomerKey = Sales.CustomerKey
and inserted.ProductKey = Sales.ProductKey
end
go
Test Script:
insert CustomersSalesProducts select 3,3,300,3,'Attribute2'

How do I insert from a table variable to a table with an identity column, while updating the the identity on the table variable?

I'm writing a SQL script to generate test data for our database. I'm generating the data in table variables (so I can track it later) and then inserting it into the real tables. The problem is, I need to track which rows I've added to the parent table, so that I can generate its child data later on in the script. For example:
CREATE TABLE Customer (
CustomerId INT IDENTITY,
Name VARCHAR(50)
)
CREATE TABLE Order (
OrderId INT IDENTITY,
CustomerId INT,
Product VARCHAR(50)
)
So, in my script, I create equivalent table variables:
DECLARE #Customer TABLE (
CustomerId INT IDENTITY,
Name VARCHAR(50)
) -- populate customers
DECLARE #Order TABLE (
OrderId INT IDENTITY,
CustomerId INT,
Product VARCHAR(50)
) -- populate orders
And I generate and insert sample data into each table variable.
Now, when I go to insert customers from my table variable into the real table, the CustomerId column in the table variable will become meaningless, as the real table has its own identity seed for its CustomerId column.
Is there a way I can track the new identity of each row inserted into the real table, in my table variable, so I can use a proper CustomerId for the order records? Or, is there a better way I should be going about this?
(Note: I originally started with an application to generate the test data, but it ran too slow during insert as > 1,000,000 records need to be generated.)
WHy do you need identity values on the table variables? If you use just int, you can isnert the ids after the insert is done. Grab them using the output clause. YOu might need an input values and an output values table varaiable to get this just right like this:
DECLARE #CustomerInputs TABLE (Name VARCHAR(50) )
DECLARE #CustomerOutputs TABLE (CustomerId INT ,Name VARCHAR(50) )
INSERT INTO CUSTOMERS (name)
OUTPUT inserted.Customerid, inserted.Name INTO #CustomerOutputs
SELECT Name FROM #CustomerInputs
SELECT * from #CustomerOutputs
You can insert the data to the table with a cursor and use the built-in function SCOPE_IDENTITY() to get the last id which was inserted in the current scope (by your script).
See this MSDN article for more information on SCOPE_IDENTITY.
Here is one way of doing it. If you can use it depends on your situation. You should not do it in production environment when users use your db.
-- Get the next identity values for Customer and Order
declare #NextCustomerID int
declare #NextOrderID int
set #NextCustomerID = IDENT_CURRENT('Customer')+1
set #NextOrderID = IDENT_CURRENT('Order')+1
-- Create tmp tables
create table #Customer (CustomerID int identity, Name varchar(50))
create table #Order (OrderID int identity, CustomerID int, Product varchar(50))
-- Reseed the identity columns in temp tables
dbcc checkident(#Customer, reseed, #NextCustomerID)
dbcc checkident(#Order, reseed, #NextOrderID)
-- Populate #Customer
-- Populate #Order
-- Allow insert to identity column on Customer
set identity_insert Customer on
-- Add rows to Customer
insert into Customer(CustomerId, Name)
select CustomerID, Name
from #Customer
-- Restore identity functionality on Customer
set identity_insert Customer off
-- Add rows to Order
set identity_insert [Order] on
insert into [Order](OrderID, CustomerID, Product)
select OrderID, CustomerID, Product
from #Order
set identity_insert [Order] off
-- Drop temp tables
drop table #Customer
drop table #Order
-- Check result
select * from [Order]
select * from Customer
The way I'd do it its first obtain the MAX(CustomerId) from your Customer Table. Then I'd get rid of the IDENTITY column on your variable table and do my own CustomerId using ROW_NUMBER() and the MaxCustomerId. It should be something like this:
DECLARE #MaxCustomerId INT
SELECT #MaxCustomerId = ISNULL(MAX(CustomerId),0)
FROM Customer
DECLARE #Customer TABLE (
CustomerId INT,
Name VARCHAR(50)
)
INSERT INTO #Customer(CustomerId, Name)
SELECT #MaxCustomerId + ROW_NUMBER() OVER(ORDER BY SomeColumn), Name
FROM YourDataTable
Or insert the values on a temp table, so you can use the same ids to fill your Order table.

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