Reserviert SELECT INTO den #Object-Namen in TempDB vor der Laufzeit?

8

Als ich einen Quickie-Prozess zusammenstellte, um beim Debuggen zu helfen, stieß ich auf einen Fehler im Compiler.

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;

Wenn Sie dies versuchen, wird der folgende Fehler zurückgegeben

Meldung 2714, Ebene 16, Status 1, Prozedur spFoo, Zeile 19
In der Datenbank befindet sich bereits ein Objekt mit dem Namen '#bar'.

In einem für Menschen lesbaren Sinne scheint der Prozess in Ordnung zu sein: Es select intowird immer nur eine Anweisung ausgeführt, da sie in die if-elseBlöcke eingeschlossen sind. Sehr gut, SQL Server kann jedoch nicht bestätigen, dass die Anweisungen logisch voneinander ausgeschlossen sind. Vielleicht verwirrender ist jedoch, dass der Fehler weiterhin besteht, wenn der Fehler drop table #fooinnerhalb des if-else-Blocks platziert wird (von dem angenommen wird, dass er den Compiler auffordert, die Zuordnung des Objektnamens aufzuheben).

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;

Der Prozess selbst ist in Ordnung. Ich saugte es auf und schrieb die create table #foo( ... )und insert #foo ( ... )-Anweisungen, ich hatte versucht, mit der select * into Syntax zu überspringen . An diesem Punkt versuche ich nur zu verstehen, warum der Compiler mich mit der Lazy-Guy-Syntax beschissen hat. Ich kann mir nur vorstellen, dass der DDL-Befehl den Objektnamen IN TEMPDB reserviert .

Warum der fette Text?

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

Dies schlägt mit demselben Fehlercode wie oben fehl. Aber die folgenden ...

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

... gelingt es. Das gleiche folgt oben auf den ursprünglichen Proc-Versuch. Damit...

Meine Frage ist dies

Was ist der Unterschied (und warum ist er vorhanden) bei der Objektnamenreservierung für TempDBObjekte im Gegensatz zu Benutzerdatenbanken? Keine der Referenzen zur Verarbeitung logischer Abfragen oder DDL-Befehlsreferenzen, die ich überprüft habe, scheinen dies zu erklären.

Peter Vandivier
quelle
1
Dieser Screenshot aus "Das Handbuch des Gurus zu gespeicherten SQL Server-Prozeduren, XML und HTML" (in Google Books) scheint relevant zu sein und zeigt, dass dies seit 7.0 so funktioniert. I.stack.imgur.com/8pDGT.png
Martin Smith
Scheint Seite 6 zu sein (FYI für alle, die später zum Thread kommen).
Peter Vandivier

Antworten:

6

Dies hat nichts mit Objektnamenreservierungen in TempDB oder irgendetwas mit Laufzeit zu tun. Dies ist einfach der Parser, der keinen Logik- oder Codepfaden folgen kann, um sicherzustellen, dass Ihr Code möglicherweise nicht zweimal versuchen kann, diese Tabelle zu erstellen. Beachten Sie, dass Sie genau den gleichen Fehler (Nicht-Laufzeit!) Erhalten, wenn Sie nur auf die Schaltfläche Analysieren ( Ctrl+ F5) klicken . Grundsätzlich, wenn Sie dies haben:

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

Der Parser sieht dies:

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

Warum funktioniert dies nicht für tatsächliche Tabellen, einschließlich der in TempDB erstellten tatsächlichen Benutzertabellen (beachten Sie, dass es auch nicht datenbankspezifisch ist)? Die einzige Antwort, die ich vorschlagen kann, ist, dass der Parser andere Regeln für # temp-Tabellen hat (es gibt auch viele andere Unterschiede). Wenn Sie genauere Gründe wünschen, müssen Sie einen Fall bei Microsoft eröffnen und prüfen, ob diese Ihnen weitere Details geben. Ich vermute, Ihnen wird gesagt: "So funktioniert es."

Einige weitere Informationen in diesen Antworten:

Aaron Bertrand
quelle
In der Tat ist " so funktioniert es " genau die Antwort, die sie haben. Na
ja