我正在尝试使用 INSERT INTO .. SELECT 查询将一组记录从一个表(在此示例中称为tblSource)插入另一个表(tblDestination),但我必须手动增加我的键值'm 插入到tblDestination而不仅仅是将其设置为 IDENTITY,因为tblDestination使用复合键。所以我有一个从 SELECT 内部运行的函数,它找到tblDestination的当前最大键值,将其递增 1,然后返回该值。
该函数如下所示:
ALTER FUNCTION [dbo].[GetNextStringID] ()
RETURNS INT AS
BEGIN
DECLARE @nextstringid INT
SELECT @nextstringid = MAX(StringID) FROM tblDestination
IF (@nextstringid IS NULL)
BEGIN
SET @nextstringid = 0
END
SET @nextstringid = @nextstringid + 1
RETURN @nextstringid
END
我的 INSERT INTO .. SELECT 语句被调用,如下所示:
INSERT INTO tblDestination(StringID, StringText)
SELECT dbo.GetNextStringID(), StringText FROM tblSource
问题是,这会导致主键冲突,因为该函数只运行一次,并且插入的所有行都使用相同的 PK 值。
有一个更好的方法吗?我可以将 tblSource 中的 PK 添加到@nextstringid 变量而不是 1,但这会产生 PK 一次跳跃多个数字而不是递增 1 的可能性,这非常混乱。也许我可以为tblSource的每一行使用行号?有没有简单的方法可以做到这一点?
我还应该注意,我知道这会产生竞争条件,如果同时从多个地方运行此查询,则会出现关键冲突。它包含在事务中,以确保在出现问题时回滚。
解决方案:
我现在从我的函数中取出以下行:
SET @nextstringid = @nextstringid + 1
这意味着它现在只返回tblDestination中的最大 ID
我现在在 INSERT INTO .. SELECT 查询中添加当前行,如下所示:
INSERT INTO tblDestination(StringID, StringText)
SELECT dbo.GetNextStringID() + ROW_NUMBER() OVER (ORDER BY tblSource.ID), StringText
FROM tblSource