SQL Server-остановить или прервать выполнение сценария SQL


есть ли способ немедленно остановить выполнение сценария SQL в SQL server, например, команду" break "или" exit"?

У меня есть скрипт, который выполняет некоторую проверку и поиск, прежде чем он начнет делать вставки, и я хочу, чтобы он остановился, если какая-либо из проверок или поисков не удастся.

18 272

18 ответов:

The raiserror метод

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

это приведет к прекращению соединения, тем самым остановив выполнение остальной части скрипта.

обратите внимание, что как уровень серьезности 20 или выше, так и WITH LOG опция необходима для того, чтобы он работал таким образом.

это даже работает с утверждениями GO, например.

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

даст вам выход:

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.

обратите внимание ,что ' ho ' не является напечатанный.

предостережения:

  • это работает только если вы вошли в систему как администратор ('sysadmin' роль), а также оставляет вас без подключения к базе данных.
  • если вы не вошли в систему как администратор, вызов RAISEERROR () сам по себе завершится ошибкой и скрипт продолжит выполнение.
  • при вызове с помощью программы sqlcmd.exe, код выхода 2745 будет сообщен.

ссылка: http://www.mydatabasesupport.com/forums/ms-sqlserver/174037-sql-server-2000-abort-whole-script.html#post761334

метод noexec

другой метод, который работает с операторами GO является set noexec on. Это приводит к тому, что остальная часть сценария будет пропущена. Он не прерывает соединение, но вам нужно включить noexec выключите снова, прежде чем какие-либо команды будут выполняться.

пример:

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.

просто используйте возврат (он будет работать как внутри, так и вне хранимой процедуры).

Если вы можете использовать режим SQLCMD, то заклинание

:on error exit

(включая двоеточие) приведет к тому, что RAISERROR фактически остановит скрипт. Например,

: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'

вывод:

Msg 50000, Level 15, State 10, Line 3
This is not a Valid Instance Database
** An error was encountered during execution of batch. Exiting.

и партия остановится. Если режим SQLCMD не включен, вы получите ошибку синтаксического анализа о двоеточии. К сожалению, это не полностью пуленепробиваемый, как если бы скрипт запускался без использования режима SQLCMD, SQL Managment Studio проносится мимо даже ошибок времени разбора! Тем не менее, если вы запускаете их из командной строки, это нормально.

Я бы не использовал RAISERROR - SQL имеет операторы IF, которые могут быть использованы для этой цели. Выполните проверку и поиск и установите локальные переменные, а затем используйте значение переменных в операторах IF, чтобы сделать вставки условными.

вам не нужно будет проверять переменный результат каждого проверочного теста. Обычно это можно сделать только с одной переменной флага, чтобы подтвердить все переданные условия:

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

даже если ваша проверка является более сложным, вы должны только нужно несколько переменных флага, чтобы включить в вашу окончательную проверку(ы).

вы можете обернуть свой оператор SQL в цикл WHILE и использовать BREAK, если это необходимо

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

Я успешно расширил решение noexec on/off с помощью транзакции, чтобы запустить скрипт полностью или ничего.

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

по-видимому, компилятор "понимает" переменную @finished в IF, даже если произошла ошибка и выполнение было отключено. Однако значение равно 1 только в том случае, если выполнение не было отключено. Следовательно, я могу красиво зафиксировать или откатить транзакцию соответственно.

в SQL 2012+, Вы можете использовать бросить.

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

от MSDN:

вызывает исключение и передает выполнение блоку CATCH конструкции TRY...CATCH... Если конструкция TRY ... CATCH недоступна, сеанс завершается. Задаются номер строки и процедура, в которой возникает исключение. Серьезность установлена на 16.

Это хранимая процедура? Если это так, я думаю, что вы могли бы просто сделать возврат, например "Return NULL";

далее уточните метод Sglasses, приведенные выше строки заставляют использовать режим SQLCMD и либо treminates scirpt, если не используется режим SQLCMD, либо использует :on error exit для выхода при любой ошибке
функция context_info используется для отслеживания состояния.

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

Я бы предложил вам обернуть соответствующий блок кода в блок try catch. Затем вы можете использовать событие Raiserror со степенью серьезности 11, чтобы разбиться на блок catch, если хотите. Если вы просто хотите поднять ошибки, но продолжить выполнение в блоке try, используйте более низкую степень серьезности.

смысл?

Ура, Джон

[отредактировано для включения BOL Ссылка]

http://msdn.microsoft.com/en-us/library/ms175976 (SQL. 90). aspx

можно использовать RAISERROR.

вы можете изменить поток выполнения с помощью перейти отчетность:

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

/* our code */

EndScript:

ни одна из этих работ с утверждениями "GO". В этом коде, независимо от того, является ли серьезность 10 или 11, вы получаете окончательный оператор печати.

Тестовый Скрипт:

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

результаты:

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

единственный способ сделать эту работу-написать сценарий без GO заявления. Иногда это просто. Иногда это довольно сложно. (Используйте что-то вроде IF @error <> 0 BEGIN ....)

Это было мое решение:

...

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

вы можете использовать оператор GOTO. Попробовать это. Это использование полностью для вас.

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

FinalStatement:
     Select @CoumnName from TableName

Thx для ответа!

raiserror() работает отлично, но вы не должны забывать return оператор в противном случае скрипт продолжается без ошибок! (hense raiserror не является "throwerror"; -)) и, конечно, делает откат, если это необходимо!

raiserror() приятно сказать человеку, который выполняет скрипт, что что-то пошло не так.

Если вы просто выполняете скрипт в Management Studio и хотите остановить выполнение или откат транзакции (если используется) при первой ошибке, то лучший способ, который я считаю, - использовать блок try catch (SQL 2005 и далее). Это хорошо работает в среде Management studio при выполнении файла сценария. Хранимой процедуре всегда можете использовать его в качестве хорошо.

Я использую RETURN здесь все время, работает в скрипте или Stored Procedure

убедитесь, что вы ROLLBACK транзакция, если вы находитесь в одном, в противном случае RETURN немедленно приведет к открытой незафиксированной транзакции