为什么此代码提供一行NULL
值而不是错误消息Must declare the scalar variable "@i".
。为什么Microsoft在t-sql中使用了这种行为?
if 1 = 0
begin
declare @i int = 1;
end;
select @i;
答案 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="
if 1 = 0
" StatementType="COND" RetrievedFromCache="false">
<Condition />
<Then>
<Statements>
<StmtSimple StatementCompId="2" StatementId="2" StatementText="
begin
 declare @i int = 1;
" StatementType="ASSIGN" RetrievedFromCache="false" />
</Statements>
</Then>
</StmtCond>
</Statements>
<Statements>
<StmtSimple StatementCompId="4" StatementId="3" StatementText="
end;

select @i;
" 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 

if 1 = 0
" StatementType="COND" RetrievedFromCache="false">
<Condition />
<Then>
<Statements>
<StmtSimple StatementCompId="2" StatementId="2" StatementText="
begin
 set @i = 1;
" StatementType="ASSIGN" RetrievedFromCache="false" />
</Statements>
</Then>
</StmtCond>
</Statements>
<Statements>
<StmtSimple StatementCompId="4" StatementId="3" StatementText="
end;

select @i;
" StatementType="SELECT WITHOUT QUERY" RetrievedFromCache="false" />
</Statements>
</Batch>