插入多行,获取 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 的每个重复组合,我想要
- 使用新 ID 在订单中创建订单条目的副本
- 获取给定副本的条目,其中 OrderType=Type2 来自 Table1
- 使用订单中新创建的条目更新其 ID table
所以最终 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
我想知道在 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 的每个重复组合,我想要
- 使用新 ID 在订单中创建订单条目的副本
- 获取给定副本的条目,其中 OrderType=Type2 来自 Table1
- 使用订单中新创建的条目更新其 ID table
所以最终 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