SQL Server - stoppen oder brechen Ausführung einer SQL-Skript
-
20-08-2019 - |
Frage
Gibt es eine Möglichkeit, um sofort die Ausführung eines SQL-Skript in SQL Server, wie eine „Pause“ oder „exit“ Befehl zu stoppen?
Ich habe ein Skript, das eine Validierung und Lookups, bevor es beginnt Einsätze tun, und ich will es stoppen, wenn eine der Validierungen oder Lookups scheitern.
Lösung
Die raiserror Methode
raiserror('Oh no a fatal error', 20, -1) with log
Damit wird die Verbindung beenden, wodurch der Rest des Skripts stoppen aus ausgeführt wird.
Beachten Sie, dass beide Schweregrad 20 oder höher und die WITH LOG
Option notwendig sind für sie auf diese Weise zu arbeiten.
Dies funktioniert sogar mit GO-Anweisungen, zum Beispiel.
print 'hi'
go
raiserror('Oh no a fatal error', 20, -1) with log
go
print 'ho'
geben Sie die Ausgabe:
hi
Msg 2745, Level 16, State 2, Line 1
Process ID 51 has raised user error 50000, severity 20. SQL Server is terminating this process.
Msg 50000, Level 20, State 1, Line 1
Oh no a fatal error
Msg 0, Level 20, State 0, Line 0
A severe error occurred on the current command. The results, if any, should be discarded.
Beachten Sie, dass 'ho' wird nicht gedruckt.
CAVEATS:
- Das funktioniert aber nur, wenn Sie als admin (sysadmin Rolle) angemeldet sind, und lässt Sie auch ohne Datenbankverbindung.
- Wenn Sie nicht angemeldet als admin sind, die Raiseerror () aufrufen, selbst scheitern und das Skript wird weiterhin ausgeführt wird .
- Wenn mit sqlcmd.exe aufgerufen, Exit-Code 2745 wird berichtet.
Die noexec Methode
Eine andere Methode, mit GO-Anweisungen arbeitet, ist set noexec on
. Dies bewirkt, dass der Rest des Skripts übersprungen werden. Es wird nicht die Verbindung beenden, aber Sie müssen, bevor irgendwelche Befehle noexec
wieder aus schalten ausführen wird.
Beispiel:
print 'hi'
go
print 'Fatal error, script will not continue!'
set noexec on
print 'ho'
go
-- last line of the script
set noexec off -- Turn execution back on; only needed in SSMS, so as to be able
-- to run this script again in the same session.
Andere Tipps
Nur eine RETURN verwenden (es wird sowohl innerhalb als auch außerhalb arbeitet eine gespeicherten Prozedur).
Wenn Sie SQLCMD-Modus verwenden können, dann ist die Beschwörung
:on error exit
(einschließlich dem Doppelpunkt) wird RAISERROR dazu führen, dass tatsächlich das Skript zu stoppen. Z.B.
:on error exit
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SOMETABLE]') AND type in (N'U'))
RaisError ('This is not a Valid Instance Database', 15, 10)
GO
print 'Keep Working'
AUSGABE:
Msg 50000, Level 15, State 10, Line 3
This is not a Valid Instance Database
** An error was encountered during execution of batch. Exiting.
und der Ansatz wird gestoppt. Wenn SQLCMD-Modus nicht eingeschaltet ist, werden Sie Parse-Fehler über den Darm bekommen. Unfortuantely, ist es nicht ganz kugelsicher als ob das Skript, ohne in SQLCMD-Modus ausgeführt wird, SQL Managment Studio Brisen rechts Vergangenheit auch Zeitfehler analysieren! wenn Sie immer noch, sie von der Kommandozeile ausgeführt wird, ist es in Ordnung.
würde ich nicht verwenden RAISERROR- SQL hat IF-Anweisungen, die für diesen Zweck verwendet werden können. Machen Sie Ihre Validierung und Lookups und setzen lokale Variablen, dann verwenden Sie den Wert der Variablen in IF-Anweisungen die Einsätze abhängig zu machen.
Sie würden keine Variable Ergebnis jeder Validierungstests überprüfen müssen. Sie könnten in der Regel mit nur einem Flagvariable tun dies alle Bedingungen, um zu bestätigen übergeben:
declare @valid bit
set @valid = 1
if -- Condition(s)
begin
print 'Condition(s) failed.'
set @valid = 0
end
-- Additional validation with similar structure
-- Final check that validation passed
if @valid = 1
begin
print 'Validation succeeded.'
-- Do work
end
Auch wenn die Validierung komplexer ist, sollten Sie nur ein paar Flag-Variablen müssen in der Endprüfung enthalten (s).
I erweitert die noexec on / off-Lösung erfolgreich mit einer Transaktion das Skript in einem alles oder nichts Art und Weise auszuführen.
set noexec off
begin transaction
go
<First batch, do something here>
go
if @@error != 0 set noexec on;
<Second batch, do something here>
go
if @@error != 0 set noexec on;
<... etc>
declare @finished bit;
set @finished = 1;
SET noexec off;
IF @finished = 1
BEGIN
PRINT 'Committing changes'
COMMIT TRANSACTION
END
ELSE
BEGIN
PRINT 'Errors occured. Rolling back changes'
ROLLBACK TRANSACTION
END
Anscheinend ist der Compiler „versteht“ die @finished Variable in der IF, auch wenn es einen Fehler gab und die Ausführung deaktiviert wurde. Allerdings ist der Wert auf 1 nur dann gesetzt, wenn die Ausführung nicht deaktiviert wurde. Daher kann ich gut dementsprechend die Transaktion oder zurückzusetzen.
Sie können Ihre SQL-Anweisung in einer while-Schleife wickeln und BREAK verwenden, wenn nötig
WHILE 1 = 1
BEGIN
-- Do work here
-- If you need to stop execution then use a BREAK
BREAK; --Make sure to have this break at the end to prevent infinite loop
END
In SQL 2012+ können Sie WURF verwenden.
THROW 51000, 'Stopping execution because validation failed.', 0;
PRINT 'Still Executing'; -- This doesn't execute with THROW
Von MSDN:
Löst eine Ausnahme und überträgt die Ausführung zu einem CATCH-Block eines TRY ... CATCH-Konstrukts ... Wenn ein TRY ... CATCH-Konstrukt nicht verfügbar ist, wird die Sitzung beendet. Die Zeilennummer und Verfahren, bei dem die Ausnahme ausgelöst wird eingestellt. Der Schweregrad wird auf 16.
Ist das eine gespeicherte Prozedur? Wenn ja, ich glaube, Sie haben soeben einen Return tun könnte, wie „Return NULL“;
Weitere refinig Sglasses Verfahren zwingen die obigen Zeilen die Verwendung von SQLCMD-Modus und entweder treminates die scirpt wenn nicht SQLCMD-Modus oder verwendet :on error exit
bei jedem Fehler
zu beenden
CONTEXT_INFO verwendet wird, den Überblick über den Zustand zu halten.
SET CONTEXT_INFO 0x1 --Just to make sure everything's ok
GO
--treminate the script on any error. (Requires SQLCMD mode)
:on error exit
--If not in SQLCMD mode the above line will generate an error, so the next line won't hit
SET CONTEXT_INFO 0x2
GO
--make sure to use SQLCMD mode ( :on error needs that)
IF CONTEXT_INFO()<>0x2
BEGIN
SELECT CONTEXT_INFO()
SELECT 'This script must be run in SQLCMD mode! (To enable it go to (Management Studio) Query->SQLCMD mode)\nPlease abort the script!'
RAISERROR('This script must be run in SQLCMD mode! (To enable it go to (Management Studio) Query->SQLCMD mode)\nPlease abort the script!',16,1) WITH NOWAIT
WAITFOR DELAY '02:00'; --wait for the user to read the message, and terminate the script manually
END
GO
----------------------------------------------------------------------------------
----THE ACTUAL SCRIPT BEGINS HERE-------------
Ich würde vorschlagen, dass Sie Ihren entsprechenden Code-Block in einem Try-Catch-Block wickeln. Sie können dann mit einem Schweregrad von 11, um den catch-Block zu brechen das Raiserror Ereignis verwenden, wenn Sie es wünschen. Wenn Sie nur raiserrors wollen aber auch weiterhin die Ausführung innerhalb des try-Block dann eine geringere Schwere verwenden.
Sinn?
Cheers, John
[Edited BOL Referenz enthalten]
http://msdn.microsoft.com/en -US / library / ms175976 (SQL.90) aspx
Sie können den Fluss der Ausführung ändern GOTO Aussagen:
IF @ValidationResult = 0
BEGIN
PRINT 'Validation fault.'
GOTO EndScript
END
/* our code */
EndScript:
Sie verwenden können RAISERROR .
Keines dieser Werke mit ‚GO‘ Aussagen. In diesem Code, unabhängig davon, ob die Schwere ist 10 oder 11, Sie die endgültige PRINT-Anweisung erhalten.
Testskript:
-- =================================
PRINT 'Start Test 1 - RAISERROR'
IF 1 = 1 BEGIN
RAISERROR('Error 1, level 11', 11, 1)
RETURN
END
IF 1 = 1 BEGIN
RAISERROR('Error 2, level 11', 11, 1)
RETURN
END
GO
PRINT 'Test 1 - After GO'
GO
-- =================================
PRINT 'Start Test 2 - Try/Catch'
BEGIN TRY
SELECT (1 / 0) AS CauseError
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE() AS ErrorMessage
RAISERROR('Error in TRY, level 11', 11, 1)
RETURN
END CATCH
GO
PRINT 'Test 2 - After GO'
GO
Ergebnisse:
Start Test 1 - RAISERROR
Msg 50000, Level 11, State 1, Line 5
Error 1, level 11
Test 1 - After GO
Start Test 2 - Try/Catch
CauseError
-----------
ErrorMessage
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Divide by zero error encountered.
Msg 50000, Level 11, State 1, Line 10
Error in TRY, level 11
Test 2 - After GO
Der einzige Weg, um diese Arbeit zu machen, ist das Skript ohne GO
Erklärungen zu schreiben. Manchmal ist das einfach. Manchmal ist es ziemlich schwierig. (Verwenden Sie so etwas wie IF @error <> 0 BEGIN ...
.)
Dies war meine Lösung:
...
BEGIN
raiserror('Invalid database', 15, 10)
rollback transaction
return
END
Sie können GOTO-Anweisung verwenden. Versuche dies. Dies ist voll für Sie verwenden.
WHILE(@N <= @Count)
BEGIN
GOTO FinalStateMent;
END
FinalStatement:
Select @CoumnName from TableName
Ich benutze RETURN
hier die ganze Zeit, arbeitet im Skript oder Stored Procedure
Stellen Sie sicher, ROLLBACK
die Transaktion, wenn Sie in einem sind, sonst RETURN
sofort in einer offenen nicht ausgeführten Transaktion führen
Thx für die Antwort!
raiserror()
funktioniert gut, aber man sollte nicht vergessen, setzt die return
Anweisung sonst das Skript ohne Fehler! (Hense die raiserror ist kein „throwError“ ;-)) und natürlich macht einen Rollback, wenn nötig!
raiserror()
ist schön, die Person zu sagen, wer das Skript ausführt, dass etwas schief gelaufen ist.
Wenn Sie einfach ein Skript in Management Studio ausgeführt wird, und wollen die Ausführung stoppen oder die Transaktion Rollback (falls verwendet) auf dem ersten Fehler, dann ist die beste Art, wie ich denke, ist zu versuchen, catch-Block zu verwenden (SQL 2005 an). Das funktioniert gut in Management Studio, wenn Sie eine Skriptdatei ausgeführt werden. Gespeicherte Prozedur kann dies immer auch verwendet werden.
Zurück in den Tag wir die folgenden Gebraucht ... am besten funktioniert:
RAISERROR ('Error! Connection dead', 20, 127) WITH LOG