更改游标内的 SET 选项 - 基于兼容性级别的不同行为

SEa*_*986 4 sql-server-2008 cursors sql-server-2016 compatibility-level

我发现数据库兼容性级别之间的一段代码的行为存在差异,并想知道其原因是什么。下面是一个简单的示例,它迭代计数表并ROWCOUNT在第 50 次迭代时更改选项:

设置:

/* Create tally table */

SELECT  TOP 100
        ROW_NUMBER() OVER (ORDER BY a.object_id) AS Number
INTO    #Tally
FROM    sys.objects a
        CROSS JOIN sys.objects b;

/* Create Some databases with different compatibility levels */

CREATE DATABASE [100Compat] WITH COMPATIBILITY_LEVEL = 100
CREATE DATABASE [110Compat] WITH COMPATIBILITY_LEVEL = 110
CREATE DATABASE [120Compat] WITH COMPATIBILITY_LEVEL = 120
CREATE DATABASE [130Compat] WITH COMPATIBILITY_LEVEL = 130
Run Code Online (Sandbox Code Playgroud)

受影响的代码:

/* cursor through the tally table */
DECLARE MyCursor CURSOR
FOR
SELECT  Number
FROM    #Tally
FOR READ ONLY;

DECLARE @num INT;

OPEN MyCursor

FETCH MyCursor
INTO @num
WHILE @@FETCH_STATUS = 0

BEGIN
    SET ROWCOUNT 0

    /* change the value for ROWCOUNT on iteration 50 */
    IF @num = 50 SET ROWCOUNT 1

    PRINT @num

    FETCH MyCursor
    INTO @num
END

SET ROWCOUNT 0

CLOSE MyCursor
DEALLOCATE MyCursor
Run Code Online (Sandbox Code Playgroud)

如果我运行上面的代码,[100Compat]它会在消息窗口中打印数字 1-100。

如果我针对 运行上面的命令[110Compat][120Compat]或者[130Compat]我可以在消息窗口中看到值 1-50 和错误消息

消息 16958,级别 16,状态 3,第 41 行 无法完成游标操作,因为自声明游标以来设置的选项已更改。

导致这种行为变化的两种兼容性模式之间的差异是什么?是否有在 110 或类似的情况下启用/禁用的跟踪标志?

我看过这篇文章,但似乎没有什么明显的原因导致了这种差异

Dan*_*man 8

SQL Server 2012 引入了对 SET ROWCOUNT 的重大更改

SET ROWCOUNT 的行为已更改,以提高许多常见查询的效率,并且可能影响兼容性级别 110 及更高级别的查询计划。当 SET ROWCOUNT 语句在 DECLARE CURSOR 语句之后和 FETCH 语句之前将 ROWCOUNT 值更改为 0 或从 0 开始时,可​​能会导致错误。要避免此错误,请将数据库兼容性级别设置为 100 或在游标语句之外设置 ROWCOUNT。

正如您的重现脚本所示,此更改由数据库兼容性级别控制。ROWCOUNT声明游标后更改设置时,兼容级别 110 (SQL 2012) 或更高版本将导致错误。