递归过程的{vars,#table和##表的可用性

时间:2018-02-09 14:02:35

标签: sql-server tsql recursion stored-procedures

如果我调用一个递归调用自身的存储过程,我想知道@vars,#tables和##表是否有非冲突的实例副本。我猜测 @vars和#tables是好的,但##应该会产生问题。

我认为这个问题进一步扩展为:当sp自己调用时,是否会创建一个新会话?

2 个答案:

答案 0 :(得分:2)

不,它没有。变量的范围限定为一个级别(因此它们对嵌套调用不可见),#temp表的作用域为会话,## temp表的作用域为全局。在T-SQL中甚至无法创建新会话(即使EXEC创建新批处理,也不创建新会话)。好吧,你可以动态创建一个预定的工作(或者可以使用本地服务器OPENROWSET),但这是作弊。

要小心在嵌套的存储过程中创建临时表:如果你不小心,你会遇到麻烦。具体而言,per the docs

  

在存储过程或触发器中创建的本地临时表   可以与之前创建的临时表具有相同的名称   调用存储过程或触发器。但是,如果是查询   引用临时表和两个具有相同的临时表   在那时存在名称,没有定义查询是哪个表   解决了。嵌套存储过程也可以创建临时存储   与由。创建的临时表同名的表   调用它的存储过程。但是,要解决修改   对于在嵌套过程中创建的表,该表必须   具有与表相同的结构,具有相同的列名   在调用过程中创建。

这意味着“明显”的情况是,您在嵌套的每个步骤中创建“相同”的临时表,如您所期望的那样:每个嵌套调用都有其“自己的”表,并且不会看到父表。但是,如果在嵌套调用中创建表,您将获得父表,如果您创建具有不同结构的表(无论出于何种原因),您实际上可以获得编译SQL Server检测到这种奇怪的情况时出错。

因此,您可以使用临时表作为保持调用状态的方式,或者特别是不通过“重新创建”它来执行此操作,但是由您来保持理智。

答案 1 :(得分:1)

  • 所有递归都在同一批次
  • 每个存储过程(递归)在批次
  • 中都有自己的范围

简单来说

  • 连接有很多批次(一个接一个)
  • 批处理有很多范围(每个代码单元,如存储的proc,函数等)

所以

  • @vars的范围是该代码单元=每次递归确定
  • #tables的范围是连接= NOT Ok,递归可见
  • ## table的范围限定为所有使用connections = NOT Ok,对递归可见