插入多行,获取 id,并对此 id 执行操作

Insert multiple rows, get ids, and perform action on this ids

我想知道在 SQL

中是否可以这样做

我有两个 table: Table1:

+----+---------+------------+-----------+
| Id | OrderId | CategoryId | OrderType |
+----+---------+------------+-----------+
|  1 |      10 |         15 | Type1     |
|  2 |      10 |         15 | Type2     |
|  3 |       9 |         17 | Type1     |
|  4 |      99 |         17 | Type2     |
|  5 |      20 |         25 | Type1     |
|  6 |      20 |         25 | Type2     |
+----+---------+------------+-----------+

这是订单 table(其 ID 在 table 1 下的 OrderId 中引用)

+----+-----------+-----------+
| Id | SomeProp1 | SomeProp2 |
+----+-----------+-----------+
|  9 | test1     | test2     |
| 99 | test1     | test2     |
| 10 | test3     | test4     |
| 20 | test5     | test6     |
+----+-----------+-----------+

现在对于 Table 1 中 OrderId-CategoryId 的每个重复组合,我想要

所以最终 table 更新如下:

Table1:

+----+---------+------------+-----------+
| Id | OrderId | CategoryId | OrderType |
+----+---------+------------+-----------+
|  1 |      10 |         15 | Type1     |
|  2 |      11 |         15 | Type2     |
|  3 |       9 |         17 | Type1     |
|  4 |      99 |         17 | Type2     |
|  5 |      20 |         25 | Type1     |
|  6 |      21 |         25 | Type2     |
+----+---------+------------+-----------+

订单:

+----+-----------+-----------+
| Id | SomeProp1 | SomeProp2 |
+----+-----------+-----------+
|  9 | test1     | test2     |
| 99 | test1     | test2     |
| 10 | test3     | test4     |
| 11 | test3     | test4     |
| 20 | test5     | test6     |
| 21 | test5     | test6     |

所以我知道如何在 Orders table 中创建行的副本并获取其 ID:

insert into Orders
(SomeProp1, SomeProp2)
SELECT 
SomeProp1, SomeProp2
from Orders

SELECT SCOPE_IDENTITY()

我知道如何在 Table 中找到重复的 ID 1:

select OrderId from Table1
    GROUP BY OrderId, CategoryId
    HAVING COUNT(OrderId) > 1

我不知道的是如何 运行 找到所有重复项。我的意思是创建某种 foreach 循环,并在此 foreach 循环中将新行插入 Orders table,获取其 ID,并使用此 ID 更新 Table1 的 OrderId 值。最让我困惑的是,如果可以执行这样的多行插入,并且每次插入时仍然能够检索 ID。

我想知道这对于单个查询来说是不是太多了,或者我以错误的方式处理这个问题(也许可以按顺序进行?)

谢谢!

这是根据以下反馈更新的版本。

原始版本只是将 OrderIds 加 1,但它们位于 IDENTITY 字段中并且 auto-created。原文 code/etc DB_fiddle

由于订单的身份字段,现在的逻辑如下

  • 如上识别所有重复项
  • 为以上创建适当数量的订单,并记录OrderIDs
  • 更新 table T1 中的相关 OrderID(其中原始行的 OrderType = 'Type 2')
  • 使用相关的 SomeProp1 和 SomeProp2
  • 更新订单 table

请注意,可以删除一个步骤(而不是插入新订单,然后更新它们),但我想非常小心,您可以将新订单与相关的旧订单相匹配。

事务在那里帮助隔离变化;但如果 运行 同时多次执行此过程,则需要小心。

这是一个 DB_Fiddle 代码如下。

/*    DATA SETUP    */

CREATE TABLE #T1 (Id int, OrderID int, CategoryId int, OrderType nvarchar(50))
INSERT INTO #T1 (Id, OrderID, CategoryId, OrderType) VALUES
(1, 10, 15, N'Type1'), 
(2, 10, 15, N'Type2'), 
(3,  9, 17, N'Type1'), 
(4, 99, 17, N'Type2'), 
(5, 20, 25, N'Type1'), 
(6, 20, 25, N'Type2')

CREATE TABLE #Orders (Id int NOT NULL IDENTITY(1,1), SomeProp1 nvarchar(50), SomeProp2 nvarchar(50))

SET IDENTITY_INSERT #Orders ON;
INSERT INTO #Orders (Id, SomeProp1, SomeProp2) VALUES
( 9, N'test1', N'test2'),
(99, N'test1', N'test2'),
(10, N'test3', N'test4'), 
(20, N'test5', N'test6')
SET IDENTITY_INSERT #Orders OFF;


/*    WORKING TABLES    */

CREATE TABLE #OrderChanges (OCId_temp int IDENTITY(1,1), OrderId_new int)

CREATE TABLE #Dupes (DupesId_temp int IDENTITY(1,1), OrderID int, CategoryId int)


/*    PROCESSING    */

BEGIN TRY
    BEGIN TRANSACTION

    INSERT INTO #Dupes (OrderID, CategoryID)
        SELECT  OrderID, CategoryID 
        FROM    #T1 
        GROUP BY OrderID, CategoryID 
        HAVING  COUNT(*) > 1

    IF EXISTS(SELECT * FROM #Dupes)
        BEGIN

        -- Create appropriate number of new orders, to get IDs (blank for the moment)
        INSERT INTO #Orders (SomeProp1, SomeProp2)
            OUTPUT  inserted.Id
            INTO    #OrderChanges (OrderID_new)
            SELECT  NULL, NULL
            FROM    #Dupes

        -- Should now have same number of rows, with matching IDENTITY Ids, in #Dupes and #OrderChanges

        -- Update #T1
        UPDATE      T1
            SET     OrderId = OC.OrderID_new
            FROM    #T1 AS T1
                    INNER JOIN #Dupes AS Dupes ON T1.OrderID = Dupes.OrderID AND T1.CategoryId = Dupes.CategoryId
                    INNER JOIN #OrderChanges AS OC ON Dupes.DupesId_temp = OC.OCId_temp
            WHERE   T1.OrderType = N'Type2'

        -- Update Orders
        UPDATE      Orders
            SET     SomeProp1 = PrevOrders.SomeProp1,
                    SomeProp2 = PrevOrders.SomeProp2
            FROM    #Orders AS Orders
                    INNER JOIN #OrderChanges AS OC ON Orders.Id = OC.OrderId_new
                    INNER JOIN #Dupes AS Dupes ON OC.OCId_temp = Dupes.DupesId_temp
                    INNER JOIN #Orders AS PrevOrders ON Dupes.OrderID = PrevOrders.Id
    
        END
    
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
    THROW;
END CATCH


/*    REPORTING AND WRAPUP     */

SELECT * FROM #T1 ORDER BY Id
SELECT * FROM #Orders ORDER BY Id

DROP TABLE #OrderChanges
DROP TABLE #Orders
DROP TABLE #T1
DROP TABLE #Dupes