是什么导致了这种奇怪的SQL行为?

Dar*_*ent 1 sql sql-server recursion stored-procedures sql-server-2005

运行SQL 2005 X64.

首先,在数据库上创建以下存储过程:

CREATE PROCEDURE dbo.Test 
    @Value int = null

AS

BEGIN

    IF (IsNull(@Value, '') = '')
        SELECT '*I am NULL!*'
    ELSE
        SELECT 'I am ' + CONVERT(varchar(20), @Value)

END
Run Code Online (Sandbox Code Playgroud)

尝试按如下方式执行上述过程,您将得到以下结果:

EXEC dbo.Test
Run Code Online (Sandbox Code Playgroud)

我是NULL!

现在,改变proc以使EXEC语句成为sproc本身的一部分:

ALTER PROCEDURE dbo.Test 
    @Value int = null

AS

BEGIN

    IF (IsNull(@Value, '') = '')
        SELECT 'I am NULL!'
    ELSE
        SELECT 'I am ' + CONVERT(varchar(20), @Value)

END

EXEC dbo.Test
Run Code Online (Sandbox Code Playgroud)

如果你现在执行它,你得到......

我是NULL!

我是NULL!

我是NULL!

... 无限广告直到输出因此错误而中断:

消息217,级别16,状态1,过程测试,第16行超出最大存储过程,函数,触发器或视图嵌套级别(限制32).

暂时忽略这根本不是一个标准做法而且很可能有人会偶然做出类似的事情,有人可能会提供一些关于SQL 2005在思考第二个版本时"思考"的低层洞察力.这个程序执行了吗?

Adr*_*iro 6

您的代码按预期运行.该过程以递归方式调用自身.

如果你希望出现这种情况,试试这个:

ALTER PROCEDURE dbo.Test 
    @Value int = null

AS

BEGIN

    IF (IsNull(@Value, '') = '')
        SELECT 'I am NULL!'
    ELSE
        SELECT 'I am ' + CONVERT(varchar(20), @Value)

END

GO

EXEC dbo.Test
Run Code Online (Sandbox Code Playgroud)

如果你使用递归,你必须定义一个基本情况(AKA"退出条件"),这将使存储过程退出递归堆栈.


Joe*_*Joe 6

递归是因为一切都被认为是proc的一部分,而不仅仅是BEGIN到END块.

从我的评论:

没什么大不了的.它将处理所有事情,直到下一个GO或批次结束的其他指标作为proc的一部分.作为过程的一部分,最外面的BEGIN和END不是必需的语法.