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.

War es hilfreich?

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.

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

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top