it-swarm.com.de

SQL Server - Stoppen oder Unterbrechen der Ausführung eines SQL-Skripts

Gibt es eine Möglichkeit, die Ausführung eines SQL-Skripts in SQL Server sofort zu stoppen, z. B. den Befehl "break" oder "exit"?

Ich habe ein Skript, das einige Überprüfungen und Suchvorgänge ausführt, bevor mit dem Einfügen begonnen wird. Ich möchte, dass es anhält, wenn eine der Überprüfungen oder Suchvorgänge fehlschlägt.

280
Andy White

Die raiserror methode

raiserror('Oh no a fatal error', 20, -1) with log

Dadurch wird die Verbindung abgebrochen und der Rest des Skripts kann nicht mehr ausgeführt werden.

Beachten Sie, dass der Schweregrad 20 oder höher und die Option WITH LOG erforderlich sind, um auf diese Weise zu arbeiten.

Dies funktioniert sogar mit GO-Anweisungen, z.

print 'hi'
go
raiserror('Oh no a fatal error', 20, -1) with log
go
print 'ho'

Gib dir 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' nicht gedruckt wird.

HÜTTEN:

  • Dies funktioniert nur, wenn Sie als Administrator angemeldet sind (Rolle 'sysadmin') und Sie lassen auch keine Datenbankverbindung.
  • Wenn Sie NICHT als Administrator angemeldet sind, schlägt der RAISEERROR () - Aufruf selbst fehl und das Skript wird weiter ausgeführt.
  • Beim Aufruf mit sqlcmd.exe wird der Beendigungscode 2745 gemeldet.

Referenz: http://www.mydatabasesupport.com/forums/ms-sqlserver/174037-sql-server-2000-abort-whole-script.html#post761334

Die noexec-Methode

Eine andere Methode, die mit GO-Anweisungen funktioniert, ist set noexec on. Dadurch wird der Rest des Skripts übersprungen. Die Verbindung wird nicht abgebrochen, Sie müssen jedoch noexec wieder deaktivieren, bevor Befehle ausgeführt werden.

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.
330
Blorgbeard

Verwenden Sie einfach ein RETURN (es funktioniert sowohl innerhalb als auch außerhalb einer gespeicherten Prozedur).

163
Gordon Bell

Wenn Sie den SQLCMD-Modus verwenden können, dann die Beschwörung 

:on error exit

(EINSCHLIESSLICH den Doppelpunkt) bewirkt, dass RAISERROR das Skript tatsächlich anhält. 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'

wird ausgeben:

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 Stapel wird angehalten. Wenn der SQLCMD-Modus nicht aktiviert ist, erhalten Sie einen Parser-Fehler zum Doppelpunkt. Leider ist es nicht völlig kugelsicher, als würde das Skript ohne SQLCMD-Modus ausgeführt. SQL Managment Studio sprudelt sogar über Zeitfehler der Analyse hinaus! Wenn Sie sie jedoch über die Befehlszeile ausführen, ist dies in Ordnung.

45
Sglasses

Ich würde RAISERROR nicht verwenden - SQL hat IF-Anweisungen, die für diesen Zweck verwendet werden können. Führen Sie Ihre Validierung und Suche durch und legen Sie lokale Variablen fest. Verwenden Sie dann den Wert der Variablen in IF-Anweisungen, um die Einfügungen bedingt zu machen.

Sie müssen kein variables Ergebnis jedes Validierungstests überprüfen. Sie können dies normalerweise mit nur einer Flagvariablen tun, um alle übergebenen Bedingungen zu bestätigen:

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

Selbst wenn Ihre Validierung komplexer ist, benötigen Sie nur wenige Flag-Variablen, um sie in Ihre abschließenden Prüfungen einzubeziehen.

20
Dave Swersky

In SQL 2012+ können Sie THROW verwenden.

THROW 51000, 'Stopping execution because validation failed.', 0;
PRINT 'Still Executing'; -- This doesn't execute with THROW

Von MSDN:

Löst eine Ausnahme aus und überträgt die Ausführung an einen CATCH-Block eines TRY… CATCH-Konstrukts ... Wenn kein TRY… CATCH-Konstrukt verfügbar ist, wird die Sitzung beendet. Die Zeilennummer und die Prozedur, in der die Ausnahme ausgelöst wird, werden festgelegt. Der Schweregrad ist auf 16 eingestellt.

12
Jordan Parker

Ich habe die Ein/Aus-Lösung von noexec erfolgreich mit einer Transaktion erweitert, um das Skript in einer Art oder 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 "versteht" der Compiler die Variable @finished in der IF, auch wenn ein Fehler aufgetreten ist und die Ausführung deaktiviert wurde. Der Wert wird jedoch nur auf 1 festgelegt, wenn die Ausführung nicht deaktiviert wurde. Daher kann ich die Transaktion entsprechend gut festlegen oder zurücksetzen.

12
Tz_

sie könnten Ihre SQL-Anweisung in eine WHILE-Schleife einschließen und bei Bedarf BREAK verwenden

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
12
Jon Erickson

Durch die weitere Verfeinerung der Sglasses-Methode erzwingen die obigen Zeilen die Verwendung des SQLCMD-Modus und zerschneiden entweder das Scirpt, wenn der SQLCMD-Modus nicht verwendet wird, oder verwendet :on error exit zum Beenden eines Fehlers
CONTEXT_INFO wird verwendet, um den Status zu verfolgen. 

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-------------
8
jaraics

Ist das eine gespeicherte Prozedur? Wenn ja, denke ich, dass Sie einfach eine Rückkehr machen könnten, wie z.

7
mtazva

Ich würde vorschlagen, dass Sie Ihren entsprechenden Codeblock in einen Try-Catch-Block einschließen. Sie können dann das Raiserror-Ereignis mit einem Schweregrad von 11 verwenden, um bei Bedarf zum Fangblock zu gelangen. Wenn Sie nur einen Fehler machen möchten, aber die Ausführung innerhalb des try-Blocks fortsetzen möchten, verwenden Sie einen niedrigeren Schweregrad.

Sinn ergeben?

Prost, John

[Um BOL-Referenz erweitert]

http://msdn.Microsoft.com/de-de/library/ms175976(SQL.90).aspx

6
John Sansom

Sie können den Ausführungsablauf mit den Anweisungen GOTO ändern:

IF @ValidationResult = 0
BEGIN
    PRINT 'Validation fault.'
    GOTO EndScript
END

/* our code */

EndScript:
6
Charlie

Nichts davon funktioniert mit 'GO'-Anweisungen. In diesem Code erhalten Sie die endgültige PRINT-Anweisung, unabhängig davon, ob der Schweregrad 10 oder 11 ist.

Test Script:

-- =================================
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

Die einzige Möglichkeit, dies zu erreichen, besteht darin, das Skript ohne GO-Anweisungen zu schreiben. Manchmal ist das einfach. Manchmal ist es ziemlich schwierig. (Verwenden Sie etwas wie IF @error <> 0 BEGIN ....)

4
Rob Garrison

sie können RAISERROR verwenden.

4
Mladen Prajdic

Das war meine Lösung:

...

BEGIN
    raiserror('Invalid database', 15, 10)
    rollback transaction
    return
END
3

Sie können die GOTO-Anweisung verwenden. Versuche dies. Dies ist voll für Sie.

WHILE(@N <= @Count)
BEGIN
    GOTO FinalStateMent;
END

FinalStatement:
     Select @CoumnName from TableName
3
Vishal Kiri

Ich verwende hier RETURN die ganze Zeit, arbeitet in Skript oder Stored Procedure

Stellen Sie sicher, dass Sie ROLLBACK für die Transaktion sind, wenn Sie sich in einer befinden, andernfalls führt RETURN sofort zu einer offenen, nicht festgeschriebenen Transaktion

2
jerryhung

Danke für die Antwort!

raiserror() funktioniert gut, aber Sie sollten die return-Anweisung nicht vergessen, da das Skript andernfalls ohne Fehler fortgesetzt wird. (Hense der Überbrücker ist kein "Throwerror" ;-)) und natürlich einen Rollback, falls nötig!

raiserror() ist nett, der Person, die das Skript ausführt, mitzuteilen, dass etwas schiefgelaufen ist.

1
hfrmobile

Wenn Sie einfach ein Skript in Management Studio ausführen und die Ausführung oder Rollback-Transaktion (falls verwendet) beim ersten Fehler anhalten möchten, ist der beste Weg, den ich denke, die Verwendung von try catch block (SQL 2005 und weiter) . Dies funktioniert gut in Management Studio, wenn Sie eine Skriptdatei ausführen .. _. Gespeicherte Prozeduren können dies ebenfalls verwenden.

1
Bhargav Shah

Am Tag haben wir folgendes verwendet ... am besten funktioniert:

RAISERROR ('Error! Connection dead', 20, 127) WITH LOG
0
Lee