Ist es "legal", #SomeTable mehr als einmal zu ERSTELLEN und ZU TROPFEN?

8

Ich habe meinen Code als "kohärente Blöcke" getrennt, die ich immer wieder in ein längeres "Konfigurationsskript" einfügen kann, und eines der Muster, die ich verwende, ist Folgendes:

CREATE TABLE #WidgetSetting 
(
    WidgetID bigint not null,
    Name nvarchar(100) not null,
    Value nvarchar(max) not null,
    CreateDate datetime not null
)

INSERT VALUES

MERGE TABLES

DROP TABLE #WidgetSetting

Aber jetzt beschwert sich SSMS, dass das Objekt beim nächsten CREATE TABLEBrand bereits vorhanden ist . Was gibt?

Ich denke, es ist offensichtlich, dass ich die Tabelle einmal am Anfang des Skripts deklarieren muss, abschneiden statt löschen, aber es ist natürlich frustrierend, nicht einfach die Tabelle löschen und denselben Namen erneut verwenden zu können.

jcolebrand
quelle
Wie Aaron weiter unten kommentierte, wäre es wahrscheinlich die einfachste Lösung, wenn dies der Weg ist, den Sie eingeschlagen haben, die #TABLE ganz am Ende des Skripts zu löschen und sie einfach in den Schritten dazwischen zu TRUNCIEREN. Dies setzt voraus, dass es nicht möglich ist, das Skript so umzugestalten, dass es überhaupt anders funktioniert. :)
Kahn
1
Genau das habe ich getan, um das Problem zu lösen. Das Verhalten hat mich nur verwirrt. Er erklärte das Warum , was ich mehr wollte als das, wie man es repariert.
Jcolebrand

Antworten:

11

Nein, mit dem Parser können Sie nicht zweimal dieselbe # temp-Tabelle im selben Stapel erstellen (und dies hat nichts mit SSMS zu tun). Es spielt nicht einmal eine Rolle, ob jemals nur eine Kopie der # temp-Tabelle erstellt werden könnte. In der folgenden bedingten Logik, die für Menschen offensichtlich immer nur einen Zweig ausführen kann, kann SQL Server dies beispielsweise nicht erkennen:

IF 1 = 1
BEGIN
  CREATE TABLE #x(i INT);
  DROP TABLE #x;
END
ELSE
BEGIN
  CREATE TABLE #x(j INT);
  DROP TABLE #x;
END

Meldung 2714, Ebene 16,
Status 1, Zeile 8 In der Datenbank befindet sich bereits ein Objekt mit dem Namen '#x'.

Und um zu beweisen, dass sich SSMS beim Kompilieren nicht beschwert (ein häufiges Missverständnis):

DECLARE @sql NVARCHAR(MAX) = N'IF 1 = 1
BEGIN
  CREATE TABLE #x(i INT);
  DROP TABLE #x;
END
ELSE
BEGIN
  CREATE TABLE #x(j INT);
  DROP TABLE #x;
END';

EXEC sp_executesql @sql;

Gibt genau den gleichen Fehler aus, obwohl SSMS nicht versucht, dynamisches SQL zu analysieren oder zu validieren, bevor es über an den Server gesendet wird sp_executesql.

Die Lösung besteht natürlich darin, dieselbe # temp-Tabelle erneut zu verwenden, anstatt sie zu löschen, jedes Mal eine andere # temp-Tabelle zu verwenden oder überhaupt keine # temp-Tabellen zu verwenden.

Dies ist nicht etwas, von dem Sie jemals erwarten sollten, dass SQL Server besser damit umgeht. Mit anderen Worten, gewöhnen Sie sich an die Problemumgehung, für die Sie sich entscheiden.

Siehe auch diese verwandte Antwort zum Stapelüberlauf, die eine alternative Erklärung gibt:

Aaron Bertrand
quelle