T-SQL:将行从一个表移动到另一个表,记录源和目标主键

时间:2018-01-16 02:18:25

标签: sql-server tsql

我觉得我大部分知道如何做到这一点,而不是如何加入它。

我会试着合理地解决这个问题:

我有3张桌子:

SliderId

我将值放入TestA:

Store.Slider

现在,当我将TestA中的行(实际上只是TestVal列值)移动到TestB时,我想向Audit添加一行,其中包含A中的主键以及B中的相应主键(其中值为正在进行中) - 然后删除A中的行。这就是我所拥有的:

CREATE TABLE [dbo].[TestA] ([PrimaryKey] [int],[TestVal] [int]);
CREATE TABLE [dbo].[TestB] ([PrimaryKey] [int],[TestVal] [int]);
CREATE TABLE [dbo].[Audit] ([PrimaryKey] [int],[SourcePrimaryKey] [int],[DestinationPrimaryKey] [int]);

所以我创建了这个临时表@pk,它可以准确地获取目标主键(因为它们在b中结束),但是我无法弄清楚如何将它们与主键进行结合在A.读取MSDN时,OUTPUT函数不一定可靠地顺序排列,所以我不能只假设来自testa的SELECT主键,其中testval> 2会产生相同的订单。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

注意:我还没有对这个问题评估MERGE方法......但我不喜欢MERGE用于非常大的数据集,因为它在大多数情况下表现不佳(与单独的DELETE / INSERT / UPDATE相比,尤其是对于列存储索引)。所以我建议其他方法。

方法1(简单)。您可以将SourcePK INT添加到TestB表并在INSERT中填充它。然后在输出中使用SourcePK和TargetPK填充Audit表,并且您不需要临时表。

方法2(差)。如果您不能将第二列添加到TestB中,但您可以将TestVal的数据类型从INT更改为BIGINT,则可以使用按位移位和按位OR / AND将SourcePK保存在TestVal中。然后,对于TestVal的每次使用,您只需要使用其一半的位。我不喜欢这种方法,因此实施(1)

更好

方法3(谨慎使用)。您可以为目标表生成PK列表,并将其映射到每个SourceID。您不需要OUTPUT,因为您只需使用映射的SourceID / TargetID执行第二次INSERT到Audit。但是您需要确保没有将数据插入目标表的并发进程。即使有并发性也有解决方法 - 您可以重新设置标识,并使用SET IDENTITY_INSERT插入范围或使用某些锁定机制

答案 1 :(得分:0)

--Create tables
DECLARE @TestA TABLE
([PrimaryKey] INT IDENTITY,
 [TestVal]    INT
);
DECLARE @TestB TABLE
([PrimaryKey] INT IDENTITY,
 [TestVal]    INT
);
DECLARE @Audit TABLE
([PrimaryKey]            INT IDENTITY,
 [SourcePrimaryKey]      INT,
 [DestinationPrimaryKey] INT
);

--Insert Values
INSERT INTO @TestA([TestVal])
VALUES(1), (2), (3), (4), (5);

--Temp table to hold key values
DECLARE @pk TABLE(b INT);

--Insert into TestB
INSERT INTO @testB(TestVal)
OUTPUT inserted.PrimaryKey
       INTO @pk
       SELECT TestVal
       FROM @testA ta
       WHERE ta.testVal > 2;

--Display what we have so far
SELECT *
FROM @TestA;
SELECT *
FROM @TestB;
SELECT *
FROM @pk;

--Insert into audit table
INSERT INTO @Audit
(SourcePrimaryKey,
 DestinationPrimaryKey
)
       SELECT ta.PrimaryKey,
              tb.PrimaryKey
       FROM @TestB tb
            JOIN @PK pk ON tb.PrimaryKey = pk.b
            JOIN @TestA ta ON tb.TestVal = ta.TestVal;  --Is test value always going to be Unque?
--Delete from testA table
DELETE FROM @TestA
WHERE TestVal IN(SELECT TestVal
                 FROM @TestB tb
                      JOIN @PK pk ON tb.PrimaryKey = pk.b);

--Display what we have 
SELECT *
FROM @TestA;
SELECT *
FROM @TestB;
SELECT *
FROM @pk;