How to make insert after insert and combine data with result ID's from first insert

爱⌒轻易说出口 提交于 2021-01-29 06:14:52

问题


DECLARE @tmpTable TABLE (UserId INT, Name nvarchar(50), Department nvarchar(50))
DECLARE @xml XML=
N'<user><userId>1</userId><name>John</name><department>A</department></user>
<user><userId>2</userId><name>Jane</name><department>B</department></user>';
insert into @tmpTable
SELECT 
    a.b.value('(./userId)[1]', 'int') AS UserId,
    a.b.value('(./name)[1]', 'nvarchar(50)') AS Name,
    a.b.value('(./department)[1]', 'nvarchar(50)') AS Department
FROM @xml.nodes('/user') a(b)
INSERT INTO members (name)
OUTPUT Inserted.MemberId
SELECT Name FROM @tmpTable

Now this outputs id's of new members. I need to make another insert to another table which require:

MemberId, UserId, Name, Department

I can't figure how to write this insert.


回答1:


You need to record/track the IDENTITY ID's that are created on the first INSERT. But you need to track in a SET based manner. (You are only tracking a single item with "OUTPUT Inserted.MemberId" I think)

Here ya go:

DECLARE @tmpTable TABLE (UserId INT, Name nvarchar(50), Department nvarchar(50))
DECLARE @xml XML=
N'<user><userId>1</userId><name>John</name><department>A</department></user>
<user><userId>2</userId><name>Jane</name><department>B</department></user>';
insert into @tmpTable
SELECT 
    a.b.value('(./userId)[1]', 'int') AS UserId,
    a.b.value('(./name)[1]', 'nvarchar(50)') AS Name,
    a.b.value('(./department)[1]', 'nvarchar(50)') AS Department
FROM @xml.nodes('/user') a(b)


create table #AUDIT ( EntityKey int not null default -1  ,  OldMyName varchar(128)  null, NewMyName varchar(128)  null , Tag varchar(64)  );



CREATE TABLE #MEMBERSREALTABLEMIMIC (MyIdentity INT IDENTITY (3001, 3) , MyName varchar(128) )

/* replace my #MEMBERSREALTABLEMIMIC with your real dbo.Member table here..i had to fake it since I don't have the DDL to dbo.Member */
INSERT INTO #MEMBERSREALTABLEMIMIC (MyName)
output inserted.MyIdentity , null , inserted.MyName , 'Employee Inserted' into #AUDIT ( EntityKey , OldMyName , NewMyName , Tag)
SELECT Name FROM @tmpTable


Select * from #MEMBERSREALTABLEMIMIC
Select * from #AUDIT


DROP table #MEMBERSREALTABLEMIMIC
DROP table #AUDIT

You can use the #AUDIT table to insert into other tables..because you have a record of the IDENTITY's now. (with the corresponding name).

Note, this may fall apart if there is not a unique constraint on "MyName".

The reason you "audit" the INSERTs is to avoid hitting dbo.Member table for the new IDENTITY's....(imagine you already had 1,000,000 rows in the dbo.Member table....the audit will prevent relooking at that table)

See

https://granadacoder.wordpress.com/2008/12/10/sqlserver20052008-output-clause-in-insertupdatedelete-statements/

Here is an example:

create table PrimaryHolderTable ( i int identity (1001,2) not null primary key, j int not null unique )
create table #OutputResultsHolder ( i int not null, j int not null)
 
insert into PrimaryHolderTable (j)
output inserted.i, inserted.j into #OutputResultsHolder
select top 10 o.object_id from sys.objects as o order by o.object_id desc --<< from sys.objects is there just to provide some rows
 

select * from #OutputResultsHolder
drop table #OutputResultsHolder, PrimaryHolderTable;

go
 
 

create table dbo.EmployeeTable ( EmpKey int identity(1001,2) ,  EmpAge int not null );
create table dbo.AuditTable ( EntityKey int not null default -1  ,  OldValue int null, NewValue int null , Tag varchar(64)  );
 
insert into dbo.EmployeeTable (EmpAge)
output inserted.EmpKey , null , inserted.EmpAge , 'Employee Inserted' into dbo.AuditTable ( EntityKey , OldValue , NewValue , Tag)
 values( 18 );

insert into dbo.EmployeeTable (EmpAge)
output inserted.EmpKey , null , inserted.EmpAge , 'Employee Inserted' into dbo.AuditTable ( EntityKey , OldValue , NewValue , Tag)
 values( 20 );

insert into dbo.EmployeeTable (EmpAge)
output inserted.EmpKey , null , inserted.EmpAge , 'Employee Inserted' into dbo.AuditTable ( EntityKey , OldValue , NewValue , Tag)
 values( 22 );
 
 
update dbo.EmployeeTable
   set EmpAge  = EmpAge + 1
output inserted.EmpKey , deleted.EmpAge, inserted.EmpAge , 'Employee Updated' into dbo.AuditTable ( EntityKey , OldValue , NewValue , Tag)
 where EmpAge <=20;
 
delete from dbo.EmployeeTable
output deleted.EmpKey , deleted.EmpAge, NULL , 'Employee Deleted'  into dbo.AuditTable (EntityKey , OldValue , NewValue , Tag)
 where EmpAge > 0;  --Test multi rows
 
select * from dbo.EmployeeTable;   --<<will be empty at this point
select * from dbo.AuditTable;
 
drop table dbo.EmployeeTable, dbo.AuditTable;
go

APPEND

Note, you canNOT "skip" the #AUDIT Table. The #AUDIT Table can only contain pieces of information from your PARENT INSERT (any properties you have and of course the new IDENTITY, which is what you are after )

Here is what I think you are after. (using the fiddle)

drop table tbl_tourSequence;
drop table tbl_tours;


create table tbl_tours (
  tourId int NOT NULL IDENTITY (1001, 5) PRIMARY KEY, 
  timeFrom smalldatetime
);
create table tbl_tourSequence (
  tourSequenceId int NOT NULL IDENTITY (2002, 3) PRIMARY KEY, 
  tour_fk int, 
  dispatchId int, 
  timeFrom smalldatetime, 
  timeTo smalldatetime
);


DECLARE @tmpTable TABLE (DispatchingId INT, TimeFrom smalldatetime, TimeTo smalldatetime)
DECLARE @xml XML=
N'<dispatch><dispatchingId>-1</dispatchingId><timeFrom>2020-07-28T07:00:00.000Z</timeFrom><timeTo>2020-07-28T07:00:00.000Z</timeTo></dispatch>
<dispatch><dispatchingId>10</dispatchingId><timeFrom>2020-07-28T07:00:00.000Z</timeFrom><timeTo>2020-07-28T07:00:00.000Z</timeTo></dispatch>

<dispatch><dispatchingId>-22</dispatchingId><timeFrom>2010-01-28T07:00:00.000Z</timeFrom><timeTo>2020-07-28T07:00:00.000Z</timeTo></dispatch>
<dispatch><dispatchingId>220</dispatchingId><timeFrom>2010-01-28T07:00:00.000Z</timeFrom><timeTo>2020-07-28T07:00:00.000Z</timeTo></dispatch>




';
insert into @tmpTable
SELECT 
    t.p.value('(./dispatchingId)[1]', 'int') AS DispatchingId,
    t.p.value('(./timeFrom)[1]', 'smalldatetime') AS TimeFrom,
    t.p.value('(./timeTo)[1]', 'smalldatetime') AS TimeTo
FROM @xml.nodes('/dispatch') t(p)


SELECT * FROM @tmpTable

create table #PARENTAUDIT ( EntityKey int not null default -1  ,  OldTimeFrom smalldatetime  null, NewTimeFrom smalldatetime null , Tag varchar(64)  );

INSERT INTO tbl_tours (TimeFrom)
output inserted.tourId , null , inserted.TimeFrom , 'TOUR Inserted' into #PARENTAUDIT ( EntityKey , OldTimeFrom , NewTimeFrom , Tag)
SELECT DISTINCT TimeFrom FROM @tmpTable

/* NOTE THE DISTINCT ABOVE, this solution depends on some unique contraint that maps the parents and the children.  here we use TimeFrom */


SELECT '#PARENTAUDIT' , * from #PARENTAUDIT


INSERT INTO tbl_tourSequence ( tour_fk , dispatchId , timeFrom , timeTo )
SELECT pa.EntityKey , tt.DispatchingId , tt.TimeFrom , tt.TimeTo
FROM #PARENTAUDIT pa JOIN @tmpTable tt on pa.NewTimeFrom = tt.TimeFrom



DROP TABLE  #PARENTAUDIT 


Select * from tbl_tours

Select * from tbl_tourSequence


来源:https://stackoverflow.com/questions/63139496/how-to-make-insert-after-insert-and-combine-data-with-result-ids-from-first-ins

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!