So unterbrechen Sie die SQL-Skriptausführung

16

Ich arbeite an SQL-Skript und muss das Skript nicht mehr fortsetzen, wenn einige Bedingungen nicht erfüllt sind.

Wenn ich es google, habe ich festgestellt, dass der RaisError mit 20 Schweregraden es beenden wird. Aber aus bestimmten Gründen kann ich diese Option nicht verwenden.

Können Sie mir bitte die möglichen Alternativen zum Stoppen der Ausführung von SQL-Skripten nennen?

Neuer Entwickler
quelle
1
Warum ist das Auslösen eines Fehlers nicht akzeptabel? Ist dieses Skript auch eine gespeicherte Prozedur?
Namphibian
Ich habe Ihre erste Frage nicht klar verstanden. Für die zweite Frage; Nein, dies ist kein SP
Neuer Entwickler
1
Was ist das Drehbuch? Besteht es aus mehreren Chargen? Hast du die Antworten hier gesehen?
Martin Smith

Antworten:

8

Aus der RAISERROR-Dokumentation (Schwerpunkt Mine):

Schweregrade von 0 bis 18 können von jedem Benutzer angegeben werden. Schweregrade von 19 bis 25 können nur von Mitgliedern der festen Serverrolle sysadmin oder von Benutzern mit ALTER TRACE-Berechtigungen angegeben werden. Für Schweregrade von 19 bis 25 ist die Option WITH LOG erforderlich.

Es ist sehr wahrscheinlich, dass der Principal, den Sie ausführen, diese Kriterien nicht erfüllt.

Es ist nichts Falsches an der Verwendung RAISERROR; Sie verwenden nur einen übermäßigen Schweregrad. Ich verwende Level 16 als Standard für einen Fehler, der ausgelöst wird und die Sequenz wird beendet. Wenn Sie genauer sein möchten, können Sie die von Microsoft selbst angegebenen Stufen befolgen:

Bildbeschreibung hier eingeben

Nach alledem ist die Verwendung RAISERRORmöglicherweise nicht ausreichend , je nach Kontext des Skripts, da das Skript nicht von selbst "beendet" wird (bei normalen Schweregraden).

Beispielsweise:

RAISERROR(N'Test', 16, 1);

SELECT 1;   /* Executed! */

Dies wird sowohl einen Fehler auslösen und eine Ergebnismenge zurück.

Um das Skript sofort zu beenden, bevorzuge ich die Verwendung RETURN(von GOTOKonstrukten des Typs -type wird in den meisten Programmierkreisen, in denen es Alternativen gibt, generell abgeraten):

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */

Oder behandeln Sie den Fehler mit TRY/CATCH, der dazu führt, dass die Ausführung zum CATCHBlock springt, wenn der Schweregrad 11 oder höher ist:

BEGIN TRY
    RAISERROR(N'Test', 16, 1);
    SELECT 1;   /* Not executed */
END TRY
BEGIN CATCH
    SELECT 2;   /* Executed */
END CATCH

BEGIN TRY
    RAISERROR(N'Test', 10, 1);
    SELECT 1;   /* Executed */
END TRY
BEGIN CATCH
    SELECT 2;   /* Not executed */
END CATCH

Ein separates Problem besteht darin, dass das Skript mehrere Stapel umfasst undRETURN nur den Stapel beendet :

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

SELECT 2;   /* Executed! */

Um dies zu beheben, können Sie @@ERRORzu Beginn jedes Stapels Folgendes überprüfen :

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
    RETURN;

SELECT 2;   /* Not executed */

Bearbeiten: Wie Martin Smith in den Kommentaren richtig hervorhebt, funktioniert dies nur für 2 Chargen. Um auf 3 oder mehr Stapel zu erweitern, können Sie Fehler wie GOTOfolgt kaskadieren (Hinweis: Die Methode löst dieses Problem nicht, da das Zieletikett innerhalb des Stapels definiert werden muss):

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
BEGIN
    RAISERROR(N'Error already raised. See previous errors.', 16, 1);
    RETURN;
END

SELECT 2;   /* Not executed */
GO

IF (@@ERROR != 0)
BEGIN
    RAISERROR(N'Error already raised. See previous errors.', 16, 1);
    RETURN;
END

SELECT 3;   /* Not executed */

Oder, wie er auch betont, Sie können die SQLCMDMethode verwenden, wenn dies für Ihre Umgebung geeignet ist.

Jon Seigel
quelle
Dieser letzte Vorschlag funktioniert nicht. Siehe Pastebin . Ich mag die sqlcmd-Methode hier
Martin Smith
6

Sie können die GOTOAnweisung verwenden, um herumzuspringen, wo immer Sie möchten. Mit anderen Worten, Sie haben einen Fehler oder eine andere Bedingung, und Sie können eine Beschriftung am unteren Rand des Skripts (dh TheEndOfTheScript:) haben und nur eine goto TheEndOfTheScript;Anweisung ausgeben .

Hier ist ein kurzes Beispiel:

print 'here is the first statement...';

print 'here is the second statement...';

-- substitute whatever conditional flow determining factor
-- you'd like here. I have chosen a dummy statement that will
-- always return true
--
if (1 = 1)
    goto TheEndOfTheScript;

print 'here is the third statement...';

print 'here is the fourth statement...';


TheEndOfTheScript:
print 'here is the end of the script...';

Die Ausgabe dieser Ausführung sieht folgendermaßen aus:

here is the first statement...
here is the second statement...
here is the end of the script...

Wie Sie sehen, GOTOhat der das Drucken der dritten und vierten Anweisung übersprungen und ist direkt zum Etikett ( TheEndOfTheScript) gesprungen .

Thomas Stringer
quelle
7
Funktioniert nur, wenn es einen einzelnen Stapel gibt, wird abgebrochen, sobald Sie eine GO-Anweisung haben.
Gabriel
0

Stimmen Sie mit dem SET NOEXEC ON/OFFüberein, aber in gespeicherten Prozessen (die einen einzelnen Block enthalten) verwende ich einfach RETURNAnweisung.

Vorsichtsmaßnahmen: Wenn Sie in einer Skriptdatei mehrere GOAnweisungen haben, RETURNwird nur der aktuelle Block verlassen und mit dem nächsten Block / Stapel fortgefahren.

Hinweis: GOTOSollte eine schlechte Codierungspraxis sein, wird die Verwendung von " TRY..CATCH" empfohlen, da es seit SQL Server 2008 eingeführt wurde, gefolgt von THROW2012.

Eddie Kumar
quelle