SQL 序列在 case 语句中使用时会跳过值

SQL Sequence is skipping values when used in a case statement

提问人:Ian 提问时间:8/16/2022 更新时间:8/16/2022 访问量:268

问:

使用 SQL Server 2016,当另一个值不为 null 时,我尝试使用序列自动将值插入到列中。但是,如果大小写值为 null,则下一个非 null NEXT VALUE FOR 将增加其前面的 null 值。我不确定如何防止这种情况发生。代码如下:

用于创建序列的存储过程的相关部分:

DECLARE @IdMax INT;
SELECT @IdMax = (MAX(CAST(Id AS Int)) + 1) from [db].[dbo].[table] WHERE ISNUMERIC(Id) = 1;

EXEC('CREATE SEQUENCE Id_Sequence
START WITH ' + @IdMax + '
INCREMENT BY 1
CACHE 1000;')

而粗略的测试实现:

DECLARE @StartDate date
SET @StartDate = '20220816'

DECLARE @IDSequenceValue int
SET @IDSequenceValue = CAST(NEXT VALUE FOR Id_Sequence as nvarchar(7))

INSERT INTO dbo.table ( 
StartDate, 
Id) 
Values (
@StartDate,
CASE
    WHEN @StartDate IS NULL THEN NULL
    ELSE @IdSequenceValue
END);

该代码已被删节,以删除可识别的信息。我必须将 NEXT VALUE FOR 语句声明为变量,以避免无法直接在 Case 语句中使用它。我的删节输出是:

StartDate   Id
2022-08-17  5078561
NULL        NULL
NULL        NULL
2022-08-17  5078558
2022-08-17  5078557
NULL        NULL
2022-08-17  5078555
2022-08-17  5078554
2022-08-17  5078553

这个问题可以克服吗?我在这里不知所措。谢谢!

SQL Server 序列

评论

2赞 Aaron Bertrand 8/16/2022
您正在根据表中的当前最大值在数据库中创建序列对象?这似乎是很多额外的脚手架,以及一个并发杀手(不仅因为你必须在其他人运行代码之前删除序列,还因为你没有足够的语义来保护你免受其他人在你和你最终插入之间插入另一个)。IdSELECT (MAX+1)
0赞 Alex 8/16/2022
亚伦提出了一个有效的观点。能否提供有关您的流程的更多信息?是数据导入/处理作业吗?您是使用RBAR方法(例如游标)还是使用基于集合的逻辑?
3赞 Dale K 8/16/2022
仅供参考,这是一个表达,而不是一个陈述CASE
1赞 Aaron Bertrand 8/16/2022
对于基于集合的逻辑,您可以查看如下内容。如果您使用光标一次插入一行,那么,仅在日期不为 NULL 时递增序列,如下所示。但我仍然认为在这种情况下序列是矫枉过正的——只需递增你自己的计数器,它不需要单个会话使用的可序列化对象,也不需要动态 SQL。
2赞 Dale K 8/17/2022
@BenThul这个网站不仅仅是为了解决OP的问题,它还是关于最佳实践的,包括确保OP使用(并理解)正确的术语。而且(不是在这种情况下),但很多时候,当人们提出涉及它的问题时,他们将其用作绊倒他们的陈述这一事实。CASE

答:

1赞 Md. Suman Kabir 8/16/2022 #1

问题是,您总是通过以下语句生成下一个序列号:

SET @IDSequenceValue = CAST(NEXT VALUE FOR Id_Sequence as nvarchar(7))

在表达式中,有条件地使用该值。为了解决这个问题,我建议仅在需要像这样使用时才生成下一个序列号:CASE

if @StartDate IS NOT NULL
    begin
        SET @IDSequenceValue = CAST(NEXT VALUE FOR Id_Sequence as nvarchar(7))
    end

评论

1赞 Alex 8/16/2022
“消息 11741,级别 15,状态 1,第 19 行 NEXT VALUE FOR 函数不能在 CASE、CHOOSE、COALESCE、IIF、ISNULL 和 NULL 中使用。
0赞 Md. Suman Kabir 8/16/2022
@Alex已更正