运行 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
尝试按如下方式执行上述过程,然后得到以下结果:
EXEC dbo.Test
我是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
如果你现在执行它,你会得到......
我是NULL!
我是NULL!
我是NULL!
... ad infinitum 直到输出因此错误而中断:
Msg 217,Level 16,State 1,Procedure 测试,第16行最大存储量 程序,功能,触发器或视图 超出嵌套级别(限制32)。
暂时忽略这根本不是标准做法,并且很可能有人会偶然做出类似这样的事情,有人可以提供一些关于SQL 2005“思考”的低级别见解。执行这个过程的第二个化身?
答案 0 :(得分:6)
您的代码按预期运行。该程序自称为recursively。
如果不想要,请尝试以下操作:
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
如果确实希望使用递归,则必须定义base case(AKA“退出条件”),这将使存储过程退出递归堆栈。
答案 1 :(得分:6)
递归是因为一切都被认为是proc的一部分,而不仅仅是BEGIN到END块。
来自我的评论:
没什么大不了的。它将处理所有事情,直到下一个GO或批次结束的其他指标作为proc的一部分。作为过程的一部分,最外面的BEGIN和END不是必需的语法。
答案 2 :(得分:1)
正如其他人所提到的那样,它被称为递归。
您可以避免使用@Adrian显示(使用'GO'来阻止sp调用自身),或者您也可以使用控制结构将其转义...
如果您想了解递归,可以学习以下示例/实验:http://msdn.microsoft.com/en-us/library/aa175801.aspx
答案 3 :(得分:1)
它允许32个嵌套调用。每次执行Exec时,您都会永远嵌套它。所以递归思考。
执行程序 选择 EXEC 选择 EXEC 无限。
一旦达到第32次嵌套调用,就会达到最大值,然后说我无法继续。
答案 4 :(得分:0)
我对这个问题的解读并不是“为什么我的SP会出现递归?”但是“为什么递归限制在32以及如何绕过它?”
我完全忘记了SQL Recursion会像你那样死在你身上。
我刚刚解决的答案是使用TRY-CATCH和@@ NestLevel。以下是一个小型示范装置。在你的代码中,拥有一个独立的结束条件会好得多,例如用完要处理的块。
我的代码被编辑器破坏了,我没有时间处理你的问题。
BEGIN TRY DROP PROCEDURE dbo.Nester END TRY BEGIN CATCH END catch
GO CREATE PROCEDURE dbo.Nester @NestLevel INT = 0 OUT 如 开始 DECLARE @MaxActNestLevel INT = 40;
SELECT @NestLevel += 1;
PRINT (CONVERT(sysname, @@NestLevel) + ' ' + CONVERT(sysname, @NestLevel))
IF @NestLevel < @MaxActNestLevel
BEGIN TRY
EXEC dbo.Nester @NestLevel OUT
END TRY
BEGIN CATCH
PRINT 'Catch Block'
PRINT (ERROR_NUMBER())
SELECT @NestLevel += 1;
IF @@NestLevel < 30 --AND ERROR_NUMBER() = 217
BEGIN
EXEC dbo.Nester @NestLevel OUT
END
ELSE
THROW
END CATCH
END 走 EXEC dbo.Nester;