访问未声明的变量

时间:2016-12-26 09:35:42

标签: sql-server tsql

为什么此代码提供一行NULL值而不是错误消息Must declare the scalar variable "@i".。为什么Microsoft在t-sql中使用了这种行为?

if 1 = 0
begin
    declare @i int = 1;
end;

select @i;

2 个答案:

答案 0 :(得分:4)

来自MSDN

  

变量的范围是Transact-SQL语句的范围   可以引用变量。变量的范围从   指出它被声明直到批处理或存储过程结束   宣布它。

因此,在您的示例中,@i变量的范围是批次或过程 ,其中定义了它们。

所以下一个查询: -

if 1 = 0
begin
    declare @i int = 1
end
else
begin
    declare @i int = 3
end

select @i

正在检索下一个错误: -

  

变量名'@i'已经声明。变量名称必须   在查询批处理或存储过程中是唯一的。

但您的查询没有。

<强>更新

微软表示他们不会解决这个问题: -

Make it possible to declare variables that are only visible within a block.

答案 1 :(得分:3)

DECLARE的范围是当前批次,而不是代码块。 所以编译器看到你的变量是可以的。

问题是 - 如果它可见,为什么不分配。赋值与常规赋值相同,只是在变量声明中内联编写。分配是受代码流影响的命令。以下是代码的实际执行计划:

<Batch>
  <Statements>
    <StmtCond StatementCompId="1" StatementId="1" StatementText="&#xD;&#xA;if 1 = 0&#xD;" StatementType="COND" RetrievedFromCache="false">
      <Condition />
      <Then>
        <Statements>
          <StmtSimple StatementCompId="2" StatementId="2" StatementText="&#xA;begin&#xD;&#xA;    declare @i int = 1;&#xD;" StatementType="ASSIGN" RetrievedFromCache="false" />
        </Statements>
      </Then>
    </StmtCond>
  </Statements>
  <Statements>
    <StmtSimple StatementCompId="4" StatementId="3" StatementText="&#xA;end;&#xD;&#xA;&#xD;&#xA;select @i;&#xD;&#xA;" StatementType="SELECT WITHOUT QUERY" RetrievedFromCache="false" />
  </Statements>
</Batch>

及以下是扩展声明和分配的计划:

declare @i int 

if 1 = 0
begin
    set @i = 1;
end;

select @i;

<Batch>
  <Statements>
    <StmtCond StatementCompId="1" StatementId="1" StatementText="declare @i int &#xD;&#xA;&#xD;&#xA;if 1 = 0&#xD;" StatementType="COND" RetrievedFromCache="false">
      <Condition />
      <Then>
        <Statements>
          <StmtSimple StatementCompId="2" StatementId="2" StatementText="&#xA;begin&#xD;&#xA;    set @i = 1;&#xD;" StatementType="ASSIGN" RetrievedFromCache="false" />
        </Statements>
      </Then>
    </StmtCond>
  </Statements>
  <Statements>
    <StmtSimple StatementCompId="4" StatementId="3" StatementText="&#xA;end;&#xD;&#xA;&#xD;&#xA;select @i;&#xD;&#xA;" StatementType="SELECT WITHOUT QUERY" RetrievedFromCache="false" />
  </Statements>
</Batch>