I am inserting multiple rows into Table1 using table-valued parameter.
Now I want to insert Table1's scope identity to Table2 with some values.
How do I achieve that?
You can use the Output Clause clause for that, lets look at a sample
suppose your Table1 looks like this
Table1(Table1_ID int identity, Name varchar(100), Email varchar(100), ...)
Now lets insert and catch all new ID's and Names :
declare #OutputTbl table (ID INT, Name varchar(100))
insert into Table1(Name, Email)
output inserted.Table1_ID, inserted.Name into #OutputTbl(ID, Name)
VALUES ('john doe', 'john#somewhere.com'),
('Anna', 'Anna#1com')
select * from #OutputTbl
the result in #OutputTbl will be
ID Name
-- --------
18 john doe
19 Anna
Now you can off course insert all rows from #OutputTbl into another table if you so desire
insert into Table2 (Table1_ID, Name)
select ID, Name
from #OutputTbl
Related
I have two tables in MS SQL:
CREATE TABLE Table1 (ID INT IDENTITY(1,1) NOT NULL, TEXTVal VARCHAR(100), Table2Id int)
insert into Table1 (TEXTVal) values('aaa');
insert into Table1 (TEXTVal) values('bbb'); insert into Table1 (TEXTVal) values('ccc');
CREATE TABLE Table2 (ID INT IDENTITY(1,1) NOT NULL, TEXTVal VARCHAR(100), Table2Id int)
Id are identity columns. I want to copy TEXTVal values from Table1 to Table2:
INSERT INTO Table2 (TEXTVal)
SELECT TEXTVal FROM Table1
where TEXTVal <> 'ccc'
and after that update column Table2Id in Table1 with appropriate values of Id from Table2. I can do this with cursor and SCOPE_IDENTITY().
I am just wondering, is there a way to do it without cursor in T-SQL?
As Jeroen stated in comments, you'll want to use OUTPUT. In the following example if you don't have an AdventureWorks database, just use a test database. You should be able to copy/paste this and just run it to see it in action!
USE AdventureWorks;
GO
----Creating the table which will store permanent table
CREATE TABLE TestTable (ID INT, TEXTVal VARCHAR(100))
----Creating temp table to store ovalues of OUTPUT clause
DECLARE #TmpTable TABLE (ID_New INT, TEXTVal_New VARCHAR(100),ID_Old INT, TEXTVal_Old VARCHAR(100))
----Insert values in real table
INSERT TestTable (ID, TEXTVal)
VALUES (1,'FirstVal')
INSERT TestTable (ID, TEXTVal)
VALUES (2,'SecondVal')
----Update the table and insert values in temp table using Output clause
UPDATE TestTable
SET TEXTVal = 'NewValue'
OUTPUT Inserted.ID, Inserted.TEXTVal, Deleted.ID, Deleted.TEXTVal INTO #TmpTable
WHERE ID IN (1,2)
----Check the values in the temp table and real table
----The values in both the tables will be same
SELECT * FROM #TmpTable
SELECT * FROM TestTable
----Clean up time
DROP TABLE TestTable
GO
ResultSet:
TmpTable:
ID_New TextVal_New ID_Old TextVal_Old
——————— ——————— ——————— ———————
1 NewValue 1 FirstVal
2 NewValue 2 SecondVal
Original Table:
ID TextVal
——————— ———————
1 NewValue
2 NewValue
As you can see it is possible to capture new values, and the values you are updating. In this example I'm just stuffing them into a table variable but you could do whatever you'd like with them. :)
I can use the OUTPUT keyword of the insert statement to insert new data to a table and output to a temporary table.
The input table which to be inserted into another table have an Id I need to pass to the temporary table but not the table I going to insert into. This temporary table will later have to use to do extra insertion to the other table.
INSERT INTO table1 (Name, Age)
OUTPUT inserted.Id, User.Id (??) INTO TemporaryTable
SELECT Name, Age FROM User
Is there a way to do it? Because the next insertion will need the new table1.Id with the User.Id, so I can migrate some data.
Instead of using the Temporary table you can use Variable so that it will not occupy more memory.
create table table1
(
id int NOT NULL,
,name varchar(50)
,age int,
PRIMARY KEY (id)
)
insert into table1 (name,age) values ('name', 10)
declare #extracolumn as int = scope_identity()
select #extracolumn
use this #extracolumn in next insert operation.
Have you included the extra column in the schema of the temporary table?
create table table1
(
id int
,name varchar(50)
,age int
)
declare #TemporaryTable table -- or Create table #TemporaryTable
(
id int,
userid int -- defining the extra column
);
declare #extracolumn as int = 100;
-- or declare #extracolumn as int = (select value from table where condition)
-- note that subqueries cannot be added directly in the output clause
-- so need to declare and set a variable that holds the value
insert into table1
output inserted.id,#extracolumn into #TemporaryTable -- or #TemporaryTable
values(1,'name',10)
select * from #TemporaryTable
Output is
id userid
1 100
I have a table tblemployee with this sample data:
srno name Lastname
------------------------
1 Ibrahim shaikh
2 ibrahim mohammed
3 ibrahim khan
4 paul haymen
And I have a stored procedure SPGetEmp. When I execute the procedure like this:
SPGetEmp 'ibrahim',''
it is returning this result data:
srno name Lastname
------------------------
1 Ibrahim shaikh
2 ibrahim mohammed
3 ibrahim khan
Now I want to filter the data from another stored procedure, like now I want to filter the data with last name, for example 'shaikh'.
Result should be:
srno name Lastname
-----------------------
1 Ibrahim shaikh
What should I do?
You'll need to insert the results into a temp table or variable, and then execute a SELECT query with the desired WHERE clause. For example:
DECLARE #results TABLE(
srno int
, name nvarchar(30)
, Lastname nvarchar(30)
);
INSERT INTO #results
EXEC SPGetEmp 'ibrahim','';
SELECT srno, name, Lastname
FROM #results
WHERE Lastname = 'shaikh';
Consider adding the criteria to the SPGetEmp proc as that will perform better if often executed.
You cannot filter or join the result of stored procedure becase what it returns is not a table even if you "see" it as a table.
But you can rewrite it as an inline table valued function and then you can use it as a "parameterized" view, i.e. you can select from it, filter it, join it, like this:
create function dbo.ufn_GetEmp (#name varchar(100))
returns table
as
return
(
select srno, name, Lastname
from tblemployee
where name = #name
);
go
select *
from dbo.ufn_GetEmp('ibrahim')
where lastname = 'shaikh';
I have stored procedures that inserts/updates records in some tables. Some columns of those tables have default values or auto-increment. Here's what I have:
ALTER PROCEDURE [dbo].[Usp___NewExpense]
#iCampaignID int,
#iCategory int,
#iUserID int,
#dDate Date,
#iAmountInINR int,
#strComments VarChar(200)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.Tbl_Expenses(iCampaignID, iCategory, dDate, iAmountInINR, strComments)
VALUES (#iCampaignID, #iCategory, #dDate, #iAmountInINR, #strComments);
-- How to get the record inserted using the above statement here without using triggers
-- or another select statement, so that I can assign values to the following variables?
Declare #justInsertedValue1 type1;
Declare #justInsertedValue2 type2;
Declare #justInsertedValue3 type3;
INSERT INTO dbo.Tbl_SomeOtherTable(col1, col2, col3)
VALUES (justInsertedValue1, justInsertedValue2, justInsertedValue3);
END
GO
Tbl_Expenses has about 9 columns in which two have default values and two have auto-increment set. How can I get the just inserted record just below my INSERT statement?
I know that I can use SCOPE_IDENTITY() and then a SELECT, but a query would probably make it inefficient (am I right?).
(By getting the just inserted record, I mean values of all fields of the just inserted record)
Edit: I haven't specified values for all the fields in my INSERT statement. I want to get those values inserted automatically by SQL Server due to DEFAULT/AUTO INCREMENT constraints also.
You can use the OUTPUT clause. You can even combine both inserts into one composite:
create table T1 (ID int IDENTITY(1,1) not null,ColA varchar(10) not null)
create table T2 (ID int IDENTITY(1,1) not null,T1ID int not null,ColB varchar(10) not null)
--Look ma! no local variables at all
insert into T2 (T1ID,ColB)
select t1.ID,'def'
from (
insert into T1(ColA)
output inserted.ID
values ('abc')
) t1
select * from T1
select * from T2
Results:
ID ColA
----------- ----------
1 abc
ID T1ID ColB
----------- ----------- ----------
1 1 def
I have a situation where I need to insert multiple records/batch insert into a view which has instead of trigger. How can I retrieve the inserted identity values? I tried using the OUTPUT clause to retrieve the Id from the Inserted table but it always returns null.
Using this setup.
create table InsteadOf
(
ID int identity primary key,
Name varchar(10) not null
)
go
create view v_InsteadOf
as
select ID, Name
from InsteadOf
go
create trigger tr_InsteadOf on InsteadOf instead of insert
as
begin
insert into InsteadOf(Name)
select Name
from inserted
end
The statement
insert into v_InsteadOf(Name)
output inserted.*
select 'Name1' union all
select 'Name2'
Will give you an error.
Msg 334, Level 16, State 1, Line 4 The target table 'InsteadOf' of the
DML statement cannot have any enabled triggers if the statement
contains an OUTPUT clause without INTO clause.
Using an INTO clause with the insert instead.
declare #IDs table(ID int, Name varchar(10))
insert into v_InsteadOf(Name)
output inserted.* into #IDs
select 'Name1' union all
select 'Name2'
select *
from #IDs
Gives you 0 as a value not null.
ID Name
----------- ----------
0 Name1
0 Name2
You can put the output clause in the trigger.
create trigger tr_InsteadOf on InsteadOf instead of insert
as
begin
insert into InsteadOf(Name)
output inserted.*
select Name
from inserted
end
And the output will be generated for you when you do the insert.
insert into v_InsteadOf(Name)
select 'Name1' union all
select 'Name2'
Result:
ID Name
----------- ----------
1 Name1
2 Name2
Update:
To capture the output from the insert statement you can use insert into ... exec (...)
declare #T table
(
ID int,
Name varchar(10)
)
insert into #T
exec
(
'insert into v_InsteadOf(Name)
values (''Name1''),(''Name2'')'
)