代码之家  ›  专栏  ›  技术社区  ›  George Menoutis

递归过程上@vars、#tables和##tables的可用性

  •  1
  • George Menoutis  · 技术社区  · 8 年前

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

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

    2 回复  |  直到 8 年前
        1
  •  2
  •   Jeroen Mostert    8 年前

    不,没有。变量的作用域为一个级别(因此嵌套调用看不到它们),#临时表的作用域为会话,##临时表的作用域为全局。在T-SQL中甚至无法创建新会话(甚至 EXEC 创建新批,但不创建新会话)。嗯,您可以动态创建计划作业(或者使用 OPENROWSET 但这是作弊。

    不过,要小心在嵌套的存储过程中创建临时表:如果不小心,就会遇到麻烦。明确地 per the docs :

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

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

    因此,您可以使用临时表作为跨调用保持状态的方式,也可以不通过“重新创建”临时表来实现这一点,但要保持状态正常,这取决于您自己。

        2
  •  1
  •   gbn    8 年前
    • 所有递归都在同一个 一批
    • 每个存储过程(递归)都有自己的 范围 一批

    简单地说

    • 连接有多个批次(一个接一个)
    • 批处理有许多作用域(每个代码单元,如存储过程、函数等)

    所以

    • @变量的作用域为每个递归的代码单元=Ok
    • #表的作用域为connection=NOT Ok,对递归可见
    • ##表的作用域为所有using connections=NOT Ok,对递归可见