SELECT INTO是否在运行时之前在TempDB中保留#Object名称?


8

汇集了一个快速处理程序以帮助调试,我遇到了编译器中似乎是错误的错误。

create proc spFoo
    @param bit
as
begin
    if @param = 0
    begin 
        select * 
        into #bar
        from [master].dbo.spt_values
        -- where number between ...
    end
    else
    begin
        select top 10 * 
        into #bar
        from [master].dbo.spt_values
        order by newid();
    end;
end;

尝试执行上述操作会返回以下错误

消息2714,级别16,状态1,过程spFoo,第19
行在数据库中已经有一个名为“ #bar”的对象。

在人类可读的意义上,该proc似乎很好:select into因为它们被包装在if-else块中,所以仅将执行一条语句。但是,非常好,SQL Server无法确认这些语句在逻辑上相互排斥。也许更令人困惑的是,将drop table #fooif放置在if-else块内时(如果假定它将告诉编译器取消分配对象名),错误仍然存​​在,如下所示。

create proc spFoo
    @param bit
as
begin
    select top 1 * 
    into #bar
    from [master].dbo.spt_values

    if @param = 0
    begin 
        drop table #bar;

        select * 
        into #bar
        from [master].dbo.spt_values
        -- where number between ...
    end
    else
    begin
        drop table #bar;

        select top 10 * 
        into #bar
        from [master].dbo.spt_values
        order by newid();
    end;
end;

proc本身很好。我把它吸了起来并写了create table #foo( ... )and insert #foo ( ... )语句,我一直试图跳过select * into 语法。在这一点上,我只是想了解为什么编译器使用lazy-guy语法对我不利。我唯一想到的是DDL命令保留了对象名称IN TEMPDB

为什么要加粗文字?

create proc spIck
as
begin
    create table #ack ( col1 int );
    drop table #ack;
    create table #ack ( colA char( 1 ) );
    drop table #ack;
end;

这将失败,并显示与上面相同的错误代码。但是以下...

create proc spIck
as
begin
    create table ack ( col1 int );
    drop table ack;
    create table ack ( colA char( 1 ) );
    drop table ack;
end;

...成功。原始proc尝试与上面相同。所以...

我的问题是这个

TempDB与用户数据库相比,对象的对象名称保留有什么区别(以及为什么存在)。我已经阅读过的“逻辑查询处理”参考和DDL命令参考都没有一个可以解释这一点。


1
这张“ SQL Server存储过程,XML和HTML大师指南”中的屏幕截图(在Google图书中)似乎相关,并且表明这是自7.0 i.stack.imgur.com/8pDGT.png
Martin Smith

似乎是第6页(供以后使用该线程的任何人参考)。
彼得·范迪维尔

Answers:


6

这与TempDB中的对象名称保留无关,也与运行时无关。这仅仅是解析器无法遵循逻辑或代码路径,从而确保您的代码不可能两次尝试创建该表。请注意,如果您仅单击“分析”按钮(Ctrl+ F5),则会得到完全相同的错误(非运行时!)。基本上,如果您有:

IF 1=1 
  CREATE TABLE #foo(id1 INT);
ELSE
  CREATE TABLE #foo(id2 INT);

解析器看到以下内容:

  CREATE TABLE #foo(id1 INT);
  CREATE TABLE #foo(id2 INT);

为什么对实际表(包括在TempDB中创建的实际用户表)不起作用(请注意,它也不是特定于数据库的)?我唯一可以建议的答案是,解析器针对#temp表具有一组不同的规则(也存在许多其他差异)。如果您需要更具体的原因,则需要与Microsoft展开诉讼,看看他们是否会为您提供更多详细信息。我的猜测是,您将被告知:“这就是它的工作方式。”

这些答案提供了更多信息:


实际上,“ 这就是它的工作方式正是他们的回应。噢...
Peter Vandivier
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.