Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

dynamischer SQL-Fehler:„CREATE TRIGGER“ muss die erste Anweisung in einem Abfragestapel sein

Wenn Sie SSMS (oder ein ähnliches Tool) verwenden, um den von diesem erzeugten Code auszuführen script erhalten Sie genau den gleichen Fehler. Es könnte problemlos laufen, wenn Sie Stapeltrennzeichen eingefügt haben (GO ), aber jetzt, da Sie dies nicht tun, werden Sie auch in SSMS mit dem gleichen Problem konfrontiert sein.

Andererseits der Grund, warum Sie GO nicht eingeben können in Ihren dynamischen Skripten ist weil GO ist keine SQL-Anweisung, sondern lediglich ein Trennzeichen, das von SSMS und einigen anderen Tools erkannt wird. Wahrscheinlich ist Ihnen das bereits bewusst.

Wie auch immer, der Punkt von GO ist, dass das Tool weiß, dass der Code aufgeteilt werden sollte und seine Teile getrennt ausgeführt werden sollten . Und das separat , sollten Sie auch in Ihrem Code tun.

Sie haben also diese Optionen:

  • Fügen Sie EXEC sp_execute @sql ein direkt nach dem Teil, der den Trigger ablegt, setzen Sie dann den Wert von @sql zurück um dann den Definitionsteil seinerseits zu speichern und auszuführen;

  • Verwenden Sie zwei Variablen, @sql1 und @sql2 , speichern Sie den IF EXISTS/DROP-Teil in @sql1 , den CREATE TRIGGER in @sql2 , dann führen Sie beide Skripte (wieder separat) aus.

Aber dann, wie Sie bereits herausgefunden haben, werden Sie auf ein anderes Problem stoßen:Sie können keinen Trigger in einer anderen Datenbank erstellen, ohne die Anweisung im Kontext dieser Datenbank auszuführen .

Nun gibt es zwei Möglichkeiten, den notwendigen Kontext bereitzustellen:

1) Verwenden Sie ein USE Anweisung;

2) Führen Sie die Anweisung(en) als dynamische Abfrage mit EXEC targetdatabase..sp_executesql N'…' .

Offensichtlich wird die erste Option hier nicht funktionieren:Wir können USE … nicht hinzufügen vor CREATE TRIGGER , da letzteres die einzige Anweisung im Batch sein muss.

Die zweite Option kann verwendet werden, aber es erfordert eine zusätzliche Schicht Dynamik (nicht sicher, ob es ein Wort ist). Das liegt daran, dass der Datenbankname hier ein Parameter ist und wir daher EXEC targetdatabase..sp_executesql N'…' als ein dynamisches Skript, und da das tatsächlich auszuführende Skript selbst ein dynamisches Skript sein soll, wird es daher zweimal verschachtelt.

Also vor dem (zweiten) EXEC sp_executesql @sql; Zeile fügen Sie Folgendes hinzu:

SET @sql = N'EXEC ' + @dbname + '..sp_executesql N'''
           + REPLACE(@sql, '''', '''''') + '''';

Wie Sie sehen können, um den Inhalt von @sql einzubinden Als verschachteltes dynamisches Skript müssen sie in einfache Anführungszeichen gesetzt werden. Aus dem gleichen Grund ist jedes einzelne Anführungszeichen in @sql muss verdoppelt werden (z. B. mit REPLACE() Funktion , wie in der obigen Anweisung).