【问题标题】:Multiple Table Insert with Merge?多表插入合并?
【发布时间】:2013-08-29 07:04:22
【问题描述】:

我正在尝试在父/子关系中插入一些行。如何在 SQL 中实现这一点?

这将是我用来查找要插入的信息的基本查询:

SELECT * FROM parentTable p
INNER JOIN childTable c
    ON p.ID = c.ParentTableID
WHERE p.PlanID = 123456

需要发生的是我首先插入 ParentTable 行,这实际上只是匹配行的副本,但具有新的 PlanID 和 Created Date。然后我从插入的行中取出父表 ID,并将其用于相同的进程,但用于子表。

所以我需要在 .Net 中至少循环遍历所有 parentTable 匹配项并为每个匹配项创建 1 个 childTable 行。

我试图使用MERGEOUTPUT 子句,但似乎我可能正在使用方钉作为圆孔。使用某种类型的 CURSOR 会更好吗?


所以这就是我根据下面的答案到目前为止所得到的。不幸的是,它没有抓住SCOPE_IDENTITY()...有什么诀窍吗?因为那是返回 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

【问题讨论】:

    标签: sql sql-server merge sql-server-2008-r2


    【解决方案1】:

    你不需要MERGE,你也绝对不需要游标。而INSERT(或MERGE)一次只能影响一个表,因此无论如何您都需要执行多个语句。如果您一次只处理一个计划,您可以这样做:

    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;
    

    如果您需要引用多个新计划,它会变得有点复杂,在这种情况下,您需要使用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;
    

    但是,您应该对此非常谨慎...我在this answer over on dba.SE 中使用MERGE 链接到几个问题和未解决的错误。我也有posted a cautionary tip hereseveral others agree

    【讨论】:

    • 严格来说,您可以使用可更新的分区视图在一个语句中插入多个表......这里只是吹毛求疵。
    【解决方案2】:

    我想这就是你所追求的。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-29
      • 2011-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多