问题描述
我有两个表: 表1:
+----+---------+------------+-----------+
| 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 |
+----+---------+------------+-----------+
这是Orders表(其ID在表1中的OrderId下引用)
+----+-----------+-----------+
| Id | SomeProp1 | SomeProp2 |
+----+-----------+-----------+
| 9 | test1 | test2 |
| 99 | test1 | test2 |
| 10 | test3 | test4 |
| 20 | test5 | test6 |
+----+-----------+-----------+
现在,对于表1中OrderId-CategoryId的每个重复组合,我想
- 在具有新ID的订单中创建订单条目的副本
- 获取给定重复项的条目,其中Table1中的OrderType = Type2
- 使用“订单”表中新创建的条目更新其ID
所以最终这些表将更新如下:
表1:
+----+---------+------------+-----------+
| 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表中创建一行的副本并获取其ID:
insert into Orders
(SomeProp1,SomeProp2)
SELECT
SomeProp1,SomeProp2
from Orders
SELECT ScopE_IDENTITY()
我知道如何在表1中找到重复的ID。
select OrderId from Table1
GROUP BY OrderId,CategoryId
HAVING COUNT(OrderId) > 1
我不知道的事情是如何对找到的所有重复项运行此命令。我的意思是创建某种foreach循环,然后在此foreach循环中,将新行插入Orders表中,获取其ID,然后使用此ID更新Table1的OrderId值。最让我困惑的是,如果可以执行这样的多行插入,并且每次插入时仍能够检索ID。
我想知道对于单个查询来说这是否太多,或者我以错误的方式进行处理(也许可以按顺序进行更多操作?)
谢谢!
解决方法
这是基于以下反馈的更新版本。
原始版本仅将OrderIds加1,但是它们位于IDENTITY字段中并自动创建。 DB_fiddle
中的原始代码/等由于订单的标识字段,现在的逻辑如下
- 识别上述重复项
- 为此创建适当数量的订单,并记录OrderIDs
- 更新表T1中的相关OrderID(原始行的OrderType ='Type 2')
- 使用相关的SomeProp1和SomeProp2更新“订单”表
请注意,可以删除一个步骤(而不是插入新订单,然后更新它们),但是我要非常小心,您可以将新订单与相关的旧订单进行匹配。
交易在其中以帮助隔离更改;但是如果同时运行几次该过程,则需要小心。
这是一个带有以下代码的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,N'Type2'),(3,9,17,(4,99,(5,20,25,(6,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,(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,OrderId_new int)
CREATE TABLE #Dupes (DupesId_temp int IDENTITY(1,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