如何在没有密钥的情况下删除插入的记录?

asm*_*mgx 1 sql t-sql sql-server

我有 2 个表:Tags 和 TagsTemp。

标签有数百万行,而标签临时有数千行。

它们都是物理表。

两个表中的主键是 ID,它是自动 ID(因此 ID 的编号不同,它们不匹配)。

我必须将所有数据从 TagsTemp 移动到标签。

那很简单。我这样做了:

BEGIN TRANS
INSERT INTO Tags (C1, C2, C3)
SELECT C1, C2, C3 FROM TagsTemp

DELETE FROM TagsTemp

COMMIT
Run Code Online (Sandbox Code Playgroud)

问题在于,TagsTemp 可能在此事务期间(在插入和删除语句之间的时间内)有新记录。

我不想删除包含未插入记录的表。

我在想这样的事情:

BEGIN TRANS
INSERT INTO @T (ID, C1, C2, C3)
SELECT ID, C1, C2, C3 FROM TagsTemp

INSERT INTO Tags (C1, C2, C3)
SELECT C1, C2, C3 FROM @T

DELETE FROM TagsTemp
WHERE ID IN (SELECT ID FROM @T)

COMMIT
Run Code Online (Sandbox Code Playgroud)

但这似乎不是最好的方法和糟糕的表现。

有没有更好的解决方案来做到这一点?

注意:我无法更改表结构。

Dal*_*e K 8

对于几千行,我认为您的解决方案非常好,但只是为了让您知道另一种方法,您可以MAX(ID)从表中获取然后使用它,假设您的自动 ID 正在递增整数:

BEGIN TRAN;

DECLARE @MaxId INT;

SELECT @MaxId = MAX(ID) from TagsTemp;

INSERT INTO Tags (C1, C2, C3)
SELECT C1, C2, C3
FROM TagsTemp
WHERE ID <= @MaxId;

DELETE
FROM TagsTemp
WHERE ID <= @MaxId;

COMMIT;
Run Code Online (Sandbox Code Playgroud)

PS:不确定你的END TRANS- 我想你的意思是COMMIT


Dal*_*e K 5

Bart Hofland的启发,您实际上可以捕获插入期间正在传输的记录的 ID,只要您使用语句MERGE作为插入,如下所示:

DECLARE @IDs TABLE (ID INT PRIMARY KEY);

BEGIN TRAN;

MERGE Tags target
USING TagsTemp source
ON 0 = 1
WHEN NOT MATCHED THEN 
INSERT (C1, C2, C3) VALUES (source.C1, source.C2, source.C3)
OUTPUT source.id INTO @IDs;

DELETE
FROM TagsTemp
WHERE ID IN (SELECT ID FROM @IDs);

COMMIT;
Run Code Online (Sandbox Code Playgroud)

当您的标准不基于自动递增标识列时,这可以提供更灵活的方法。