Retrieve original and new identities mapping from SELECT INSERT statement using OUTPUT clause - sql-server

I have a table with two columns:
CREATE TABLE MyTable(
Id int IDENTITY(1,1) NOT NULL,
Name nvarchar(100) NOT NULL);
I want to duplicate the data using SELECT INSERT statement:
INSERT INTO MyTable (Name)
SELECT Name FROM MyTable
and here is the trickey part - I want to retrieve a mapping table between the original identity and the new identity:
DECLARE #idsMap TABLE (OriginalId int, NewId int)
I know I suppose to use the OUTPUT clause, but for some reason it doesn't work:
INSERT INTO MyTable (Name)
OUTPUT t.Id, INSERTED.Id INTO #idsMap (OriginalId, NewId)
SELECT Name FROM MyTable t
-- Returns error The multi-part identifier "t.Id" could not be bound.
Related questions:
can SQL insert using select return multiple identities?
Possible to insert with a Table Parameter, and also retrieve identity values?

It can be achieved using MERGE INTO and OUTPUT:
MERGE INTO MyTable AS tgt
USING MyTable AS src ON 1=0 --Never match
WHEN NOT MATCHED THEN
INSERT (Name)
VALUES (src.Name)
OUTPUT
src.Id,
inserted.Id
INTO #idsMap;

How about just adding a new column to MyTable? You can keep it around as long as you need to analysis or whatever. I have to say it seems a bit off to me to create a copy of the table but that is up to you to decide.
Something like this might work for you.
alter table MyTable
add OldID int null;
INSERT INTO MyTable (Name, OldID)
SELECT Name , Id
FROM MyTable t
select * from MyTable

Related

Can I grab the inserted IDs when doing multiple inserts?

In my head this sounds improbable, but I'd like to know if I can do it:
INSERT INTO MyTable (Name)
VALUES ('First'),
('Second'),
('Third'),
('Fourth'),
('Fifth');
SELECT INSERTED Name, ID FROM TheAboveQuery
Where ID is an auto-indexed column?
Just to clarify, I want to select ONLY the newly inserted rows.
Starting with SQL Server 2008 you can use OUTPUT clause with INSERT statement
DECLARE #T TABLE (ID INT, Name NVARCHAR(100))
INSERT INTO MyTable (Name)
OUTPUT INSERTED.ID, INSERTED.Name INTO #T
VALUES
('First'),
('Second'),
('Third'),
('Fourth'),
('Fifth');
SELECT Name, ID FROM #T;
UPDATE: if table have no triggers
INSERT INTO MyTable (Name)
OUTPUT INSERTED.ID, INSERTED.Name
VALUES
('First'),
('Second'),
('Third'),
('Fourth'),
('Fifth');
Sure, you can use an IDENTITY property on your ID field, and create the CLUSTERED INDEX on it
ONLINE DEMO
create table MyTable ( ID int identity(1,1),
[Name] varchar(64),
constraint [PK_MyTable] primary key clustered (ID asc) on [Primary]
)
--suppose this data already existed...
INSERT INTO MyTable (Name)
VALUES
('First'),
('Second'),
('Third'),
('Fourth'),
('Fifth');
--now we insert some more... and then only return these rows
INSERT INTO MyTable (Name)
VALUES
('Sixth'),
('Seventh')
select top (##ROWCOUNT)
ID,
Name
from MyTable
order by ID desc
##ROWCOUNT returns the number of rows affected by the last statement executed. You can always see this in the messages tab of SQL Server Management Studio. Thus, we are getting the number of rows inserted and combining it with TOP which limits the rows returned in a query to the specified number of rows (or percentage if you use [PERCENT]). It is important that you use ORDER BY when using TOP otherwise your results aren't guaranteed to be the same
From my previous edited answer...
If you are trying to see what values were inserted, then I assume you are inserting them a different way and this is usually handled with an OUTPUT clause, TRIGGER if you are trying to do something with these records after the insert, etc... more information would be needed.

How can return identity column value from table and insert other table in SQL Server?

I'm beginner in SQL Server and in my database I have two tables:
Table 1 with an id type bigint identity(1, 1)
Table 2 with the columns name and table1ID.
I want to insert (into table 1) and generate an id value. Then I will insert that id value into table1ID of table 2.
i change table to this and write this query:
insert into Interconnect_Traffic_Analysis_MAIN (Code_Op,Name_Op,Shomare_Tel,Duration,table1ID>>table1 id must save in this column)
select t7,t8,t9,t10 from Interconnect_Traffic_Analysis_Temp;
But how can I implement that?
Try this:
-- declare a variable to hold your newly created IDENTITY value
DECLARE #Identity BIGINT
-- insert your values into the first table
INSERT INTO dbo.Table1(list-of-columns)
VALUES(list-of-values);
-- get the newly generated IDENTITY value into your variable
SET #Identity = SCOPE_IDENTITY();
-- use that variable in your second INSERT
INSERT INTO dbo.Table2(table1Id)
VALUES(#Identity)
Update:
With your updated question with the INSERT statement, use this code to include the #Identity value:
INSERT INTO dbo.Interconnect_Traffic_Analysis_MAIN(Code_Op, Name_Op, Shomare_Tel, Duration, table1ID)
SELECT
t7, t8, t9, t10, #Identity
FROM
Interconnect_Traffic_Analysis_Temp;
You can try this:
insert into TableOne values ('abc');
insert into tableTwo values ((select SCOPE_IDENTITY()));
select SCOPE_IDENTITY() goes give you the last inserted id.
See this SQL fiddle

How to insert rows in another table based on insert in first table

If any insert happens in table A then,i need to insert the last inserted row into table B.
How can I do it by using ##rowcount.
I am trying below code.
create table table1
(
id int identity(1,1),
column1 nvarchar
)
create table table2
(
id int identity(1,1),
column1 nvarchar
)
Create procedure insert1
#column1 nvarchar
AS
Declare #t int,#column2 nvarchar
insert into table1 values(#column1)
select * from table1
set #t= (Select ##IDENTITY from table1)
Insert into table2 values (#t)
Please let me know how can i do the same by trigger.
You could write a trigger something like this:
CREATE TRIGGER trgTableAInsert
ON dbo.Table1
FOR INSERT
AS
INSERT INTO dbo.Table2(Column1)
SELECT Column1
FROM Inserted
Points to note:
a trigger is called once per statement, e.g. if your INSERT statement inserts 10 rows, the trigger is called once and Inserted contains those 10 newly inserted rows (do you want to insert all 10 of those into TableB?)
I would recommend to always use the schema prefix on tables (the dbo. part)
I would recommend to always explicitly specify the list of columns, both on an INSERT as well as a SELECT statement - don't omit those! (or you might run into messy and hard-to-debug issues when suddenly one of the tables changes)
MERGE INTO Table1 AS t1
USING MyTable ON 1=0 -- always generates "not matched by target"
WHEN NOT MATCHED BY TARGET THEN
-- INSERT into Table1:
INSERT (A, B, C) VALUES (t1.A, t1.B, t1.C)
--- .. and INSERT into Table2:
OUTPUT inserted.ID, MyTable.D, MyTable.E, MyTable.F
INTO Table2 (ID, D, E, F);

Common query to insert records for existing IDs

I want to insert new record for all the existing IDs in the table. For example,
I need to insert new record "B" to all the IDs (1, 2, 3). Likewise, whenever insert new record, it should be applied to all the IDs.
I can generate script for all IDs, but if any new ID inserted I need to generate query for that.
Is there any simple way (common query) to insert record for all IDs
without using ID?
1) Select all the ID and the new Name you want to insert with it.
2) Put that query in an INSERT statement.
INSERT INTO TABLE (ID, Name) SELECT DISTINCT ID, 'B' FROM TABLE
DECLARE #temp TABLE(id int)
INSERT INTO #temp
SELECT DISTINCT ID
FROM [yourtable]
INSERT INTO [yourtable] (ID,Name)
SELECT id,'B'
FROM #temp
or simply
INSERT INTO [yourtable] (ID,Name)
SELECT DISTINCT id,'B'
FROM [yourtable]
Does this help you?

Set A Field the same as ID (IDENTITY) in the insert

I have a Code (int) in my table, the ID is set to identity. How can I set a default value for my code to be filled by the same value az ID? I mean Identity.
You could use an after insert trigger:
create table TestTable (id int identity, col1 int)
go
create trigger TestTrigger on TestTable after insert
as begin
update TestTable
set col1 = id
where col1 is null
and id in (select id from inserted)
end
go
Test code:
insert TestTable default values
insert TestTable (col1) values (666)
insert TestTable default values
select * from TestTable
In general, I try to stay clear of triggers. In the long run using a stored procedure for insert is much more maintainable:
create procedure dbo.InsertTestRow(
#col1 int)
as
insert TestTable (col1) values (#col1)
if #col1 is null
begin
update TestTable
set col1 = id
where id = SCOPE_IDENTITY()
end
If it always has the same value - why don't you just drop that field. Otherwise it can be maintained with triggers (BEFORE INSERT one).
I'm looking for something in the
default value! If it is null it should
be filled with the same value as id
but if it is provided with some value,
it should keep that value
You could solve the issue by using coalesce in your queries instead.
create table T (ID int identity, ID2 int)
insert into T values (default)
insert into T values (null)
insert into T values (78)
select
ID,
coalesce(ID2, ID) as ID2
from T
Result
ID ID2
-- ---
1 1
2 2
3 78
Assuming your table's ID is an Identity column, you could consider using a constraint:
ALTER TABLE MyTable
ADD CONSTRAINT MyTableCodeDefault
DEFAULT IDENT_CURRENT('MyTable') FOR Code
This works for these use cases:
INSERT INTO MyTable DEFAULT VALUES
INSERT INTO MyTable ({columns NOT including 'Code'})
VALUES ({value list matching insert columns})
INSERT INTO MyTable (Code) VALUES (666)
INSERT INTO MyTable (Code) SELECT 8 UNION SELECT 13 UNION SELECT 21
But it does not work for bulk inserts:
INSERT INTO MyTable ({columns NOT including 'Code'})
SELECT {value list matching insert columns}
UNION
SELECT {value list matching insert columns}
UNION
SELECT {value list matching insert columns}
This restriction may seem onerous, but in my practical experience, it's rarely a problem. Most of the use cases I've encountered that need a default value involve user/UI 'convenience': don't force the user to pick a value if they don't want to.
OTOH, rarely do I encounter bulk insert situations where it's impractical to specify the value for the columns you're targeting.
You could use computed column, like this:
if object_id('TempTable') is not null drop table TempTable
create table TempTable (Id int identity(1,1), Code as Id)
insert into TempTable
default values
insert into TempTable
default values
insert into TempTable
default values
select * from TempTable
Of course if you have other columns, then you dont need default values:
if object_id('TempTable') is not null drop table TempTable
create table TempTable (Id int identity(1,1), Code as Id, SomethingElse int)
insert into TempTable (SomethingElse)
select 10 union all
select 11 union all
select 12
select * from TempTable
But, like zerkms said - why do you need two columns that are same?
If the field is an Identity field in SQL Server, the database engine will take care of its value. What we normally do is to read the record back (after inserting) to get to the generated Id.
EDIT: It sounds like you are trying to "override" the identity? If so, before you insert, run:
SET IDENTITY_INSERT [tableName] ON
You'll have to be careful not to insert a value that already exists. This can get tricky, though. So maybe consider removing the identity property altogether, and managing the default values yourself?

Resources