T-SQL中使用MAX()+1子查询的Insert into无法递增,有替代方法吗?

14

我有一个查询,需要在没有自增主键的表中批量插入行。

--TableA
--PK int (Primary key, no-identity)
--CustNo int
INSERT INTO TableA (PK,CustNo)
  SELECT (SELECT MAX(PK)+1 AS PK FROM TableA), CustNo
  FROM Customers

(简化的例子 - 请不要评论可能存在的并发问题 :-))

问题在于它不能为每个处理的行递增主键“PK”,我得到了主键冲突的错误。

我知道如何使用游标 / while循环来处理,但我想避免这样做,并以集合为基础的方式解决它,如果可能的话?

(运行 SQL Server 2008 Standard)


4
为什么不将该列设置为标识列? - Chandu
+1 @Cybernate - 这是一个糟糕的想法,如果你在SO上费心搜索,就会发现有大约20个类似的问题,每个问题都告诉你为什么这是一个糟糕的想法。 - JNK
长话短说:如果可以的话,我会创建一个身份 :-)。@JNK,我确实有点烦,但这是我的唯一选择,而且我想以最好的方式解决它。还请记住,我提供了一个简化的示例。 - KorsG
请详细说明您为什么不能将其作为身份标识。是的,有很多情况下存在比身份标识更好的替代方案,但如果没有有效的用途,那么身份标识就不会成为首要特性。 - paparazzo
5个回答

29
Declare @i int;

Select @i = max(pk) + 1 from tablea;

INSERT INTO TableA (PK, custno)
Select row_number() over(order by custno) + @i  , CustNo
FROM Customers

10
+1 给 Michael Buen,但我有一个建议:
"tablea" 表格可能为空,因此我们应该编写:
Select @i = isnull(max(pk),0) + 1 from tablea;

这将在尝试使用此代码时防止空值错误。


4

问题是它们都获得相同的行号,每一行的最大(PK) + 1相同。

尝试将其转换为 Max(PK) + Row_number()

我正在基于你知道这是个坏主意等方面进行工作,你的问题被简化了以便得到答案,而不是你希望如何解决这个问题。


这会有所帮助。 https://dev59.com/0WzXa4cB1Zd3GeqPPAEh - Asanka Indrajith

3

您可以:

;with T(NPK, CustNo) as (
  select row_number() over (order by CustNo), CustNo from Customers
)
insert into TableA (PK, CustNo)
  select NPK, custno from T
order by CustNo 

1
我有一个建议给你,关于SQL最佳实践是使用SEQUENCE,而且这很容易做到,只需复制和粘贴以下代码:

CREATE SEQUENCE SEQ_TABLEA AS INTEGER START WITH 1 INCREMENT BY 1 MAXVALUE 2147483647 MINVALUE 1 NO CYCLE

然后像这样使用它:

INSERT INTO TableA (PK,CustNo) VALUES (SEQ_TABLEA.NEXTVAL,123)

希望这个提示能够帮助你!

3
感谢您的回答,但原问题涉及SQL Server 2008,而SEQUENCE仅适用于SQL Server 2012及以上版本。 - KorsG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接