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 into
wird immer nur eine Anweisung ausgeführt, da sie in die if-else
Blö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 #foo
innerhalb 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 TempDB
Objekte im Gegensatz zu Benutzerdatenbanken? Keine der Referenzen zur Verarbeitung logischer Abfragen oder DDL-Befehlsreferenzen, die ich überprüft habe, scheinen dies zu erklären.
quelle
Antworten:
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:
Der Parser sieht dies:
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:
quelle