[英]Multiple Table Insert with Merge?
I am trying to insert some rows in a parent/child relationship.我正在尝试在父/子关系中插入一些行。 How does one accomplish this in SQL?
如何在 SQL 中实现这一点?
This would be the base query I'd use to find the info I would be inserting:这将是我用来查找要插入的信息的基本查询:
SELECT * FROM parentTable p
INNER JOIN childTable c
ON p.ID = c.ParentTableID
WHERE p.PlanID = 123456
What needs to happen is that I insert the ParentTable row first which is really just a copy of the matched row but with a new PlanID and Created Date.需要发生的是我首先插入 ParentTable 行,它实际上只是匹配行的副本,但具有新的 PlanID 和创建日期。 Then I take that ParentTable ID from the inserted row and use that for the same process but for the Child Table.
然后我从插入的行中获取该 ParentTable ID,并将其用于相同的过程,但用于子表。
So I need to do in .Net speak at least is where I loop through all parentTable matches and for each match create 1 childTable row.所以我需要在 .Net 中做的事情至少是我循环遍历所有 parentTable 匹配项,并为每个匹配项创建 1 个 childTable 行。
I was trying to use MERGE
and the OUTPUT
clause but it seems like I'm maybe using a square peg for a round hole.我试图使用
MERGE
和OUTPUT
子句,但似乎我可能正在使用方钉作为圆孔。 Would I be better off using a CURSOR of some sorts?使用某种 CURSOR 会更好吗?
So this is what I have so far based on the answer below.所以这就是我迄今为止根据下面的答案所做的。 Unfortunately it isn't grabbing the
SCOPE_IDENTITY()
...is there a trick to it?不幸的是,它没有抓住
SCOPE_IDENTITY()
......它有什么技巧吗? Because that is returning NULL I get FK errors on the inserts.因为那是返回 NULL,所以我在插入时遇到 FK 错误。
USE MemberCenteredPlan
DECLARE @NewPlanID BIGINT;--49727690
DECLARE @OldPlanID BIGINT;--49725211
DECLARE @NewSWReAssID BIGINT;
SET @NewPlanID = 49727690
SET @OldPlanID = 49725211
BEGIN
INSERT INTO tblSocialWorkerReAssessment
SELECT
@NewPlanID
,[Discussed]
,Discussion
,NULL
,NULL
,NULL
,CreatedBy
,GETDATE()
,NULL
,NULL
FROM tblSocialWorkerReAssessment
WHERE PlanID = @OldPlanID
SELECT @NewSWReAssID = SCOPE_IDENTITY();
INSERT INTO tblPlanDomain
SELECT
@NewPlanID
,[DomainTypeID]
,[MemberOutcomes]
,[MemberPreferences]
,[DomainDate]
,[Steps]
,[ClinicalFunctionalConcerns]
,[ReportWageES]
,[ReportWageSSA]
,@NewSWReAssID
,[CreatedBy]
,GETDATE()
,NULL
,NULL
,NEWID()
FROM tblPlanDomain
WHERE planID = @OldPlanID
END
You don't need MERGE
and you definitely don't need cursors.您不需要
MERGE
,也绝对不需要游标。 And an INSERT
(or a MERGE
) can only ever affect one table at a time, so you'll need to perform multiple statements anyway.并且
INSERT
(或MERGE
)一次只能影响一个表,因此无论如何您都需要执行多个语句。 If you are only ever dealing with one plan at a time, you can do this:如果您一次只处理一个计划,您可以这样做:
DECLARE @NewPlanID INT;
INSERT dbo.ParentTable(cols...)
SELECT cols...
FROM dbo.ParentTable WHERE PlanID = 123456;
SELECT @NewPlanID = SCOPE_IDENTITY();
INSERT dbo.ChildTable(ParentTableID, cols...)
SELECT @NewPlanID, cols...
FROM dbo.ChildTable WHERE PlanID = 123456;
If you need to reference multiple new plans, it gets a little more complicated, and in that case you would need to use MERGE
(at the present time, INSERT
's composable DML is a little on the light side - you can't reference the source table in the OUTPUT
clause).如果您需要引用多个新计划,它会变得稍微复杂一些,在这种情况下,您将需要使用
MERGE
(目前, INSERT
的可组合 DML 有点偏向于 - 您无法参考OUTPUT
子句中的源表)。
DECLARE @p TABLE(OldPlanID INT, NewPlanID INT);
MERGE dbo.ParentTable WITH (HOLDLOCK)
USING
(
SELECT ID, cols... FROM dbo.ParentTable
WHERE ID IN (123456, 234567)
) AS src ON src.ID IS NULL
WHEN NOT MATCHED THEN INSERT(cols...)
VALUES(src.cols...)
OUTPUT src.ID, inserted.ID INTO @p;
INSERT dbo.ChildTable(ParentTableID, cols...)
SELECT p.NewPlanID, t.cols...
FROM dbo.ChildTable AS t
INNER JOIN @p AS p
ON t.ParentTableID = p.OldPlanID;
However, you should be very wary about this... I link to several issues and unresolved bugs with MERGE
in this answer over on dba.SE .但是,你应该对此非常谨慎......我链接到几个问题和未解决的错误与
MERGE
在超过上dba.SE这个答案。 I've also posted a cautionary tip here我还在这里发布了一个警告提示
I think this is what you're after.我认为这就是你所追求的。
Use Northwind
GO
SET NOCOUNT ON
IF OBJECT_ID('tempdb..#OrderAuditHolder') IS NOT NULL
begin
drop table #OrderAuditHolder
end
CREATE TABLE #OrderAuditHolder
(
[OriginalOrderID] [int] NOT NULL,
[NewOrderID] [int] NOT NULL,
[CustomerID] [nchar](5) NULL,
[EmployeeID] [int] NULL,
[OrderDate] [datetime] NULL,
[RequiredDate] [datetime] NULL,
[ShippedDate] [datetime] NULL,
[ShipVia] [int] NULL,
[Freight] [money] NULL,
[ShipName] [nvarchar](40) NULL,
[ShipAddress] [nvarchar](60) NULL,
[ShipCity] [nvarchar](15) NULL,
[ShipRegion] [nvarchar](15) NULL,
[ShipPostalCode] [nvarchar](10) NULL,
[ShipCountry] [nvarchar](15) NULL,
)
declare @ExampleOrderID int
select @ExampleOrderID = (select top 1 OrderID from dbo.Orders ords where exists (select null from dbo.[Order Details] innerOD where innerOD.OrderID = ords.OrderID ) )
print '/@ExampleOrderID/'
print @ExampleOrderID
print ''
insert into dbo.Orders (CustomerID,EmployeeID,OrderDate,RequiredDate,ShippedDate,ShipVia,Freight,ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry)
output @ExampleOrderID , inserted.OrderID,inserted.CustomerID,inserted.EmployeeID,inserted.OrderDate,inserted.RequiredDate,inserted.ShippedDate,inserted.ShipVia,inserted.Freight,inserted.ShipName,inserted.ShipAddress,inserted.ShipCity,inserted.ShipRegion,inserted.ShipPostalCode,inserted.ShipCountry
into #OrderAuditHolder
Select
CustomerID,EmployeeID,OrderDate,RequiredDate,ShippedDate,ShipVia,Freight,ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry
from dbo.Orders where OrderID = @ExampleOrderID
print '/#OrderAuditHolder/'
Select * from #OrderAuditHolder
print ''
Insert into dbo.[Order Details] ( OrderID , ProductID , UnitPrice , Quantity , Discount )
Select
holder.NewOrderID , od.ProductID , od.UnitPrice , od.Quantity , od.Discount
from #OrderAuditHolder holder
join dbo.[Order Details] od on holder.OriginalOrderID = od.OrderID
/* Note, the "join" is on the OriginalOrderID, but the inserted value is the NewOrderID */
/* below is not needed, but shows results */
declare @MaxOrderID int
select @MaxOrderID = (select MAX(OrderID) from dbo.Orders ords where exists (select null from dbo.[Order Details] innerOD where innerOD.OrderID = ords.OrderID ) )
select * from dbo.[Order Details] where OrderID = @MaxOrderID order by OrderID desc
/**/
IF OBJECT_ID('tempdb..#OrderAuditHolder') IS NOT NULL
begin
drop table #OrderAuditHolder
end
SET NOCOUNT OFF
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.