1

我正在尝试使用 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
4

1 回答 1

1

要获取行号,您可以使用 sql server 的 row_number 函数

这是一个示例代码来演示您需要什么...而不是 3 使用您已经拥有的 @nextstringid 变量,您应该很好。

create table tblSource(id integer identity, StringText varchar(200))
insert into tblSource values ('test1')
insert into tblSource values ('test2')
insert into tblSource values ('test3')
insert into tblSource values ('test4')
SELECT (row_number()  over (order by id)) + 3 , id, StringText FROM tblSource t where t.id in (2,4)

请注意,我选择了 #2 和 #4,但行号仍会给出两个连续的 ID(在本例中为 1+3 和 2+3(4 和 5)

希望能帮助到你。

于 2013-06-11T18:24:17.263 回答