Pergunta

Existe uma maneira de execução imediatamente parada de um script SQL no servidor SQL, como um "break" ou comando "exit"?

Eu tenho um script que faz alguma validação e pesquisas antes de começar a fazer inserções, e eu quero que ele pare de se alguma das validações ou pesquisas de falhar.

Foi útil?

Solução

O href="http://msdn.microsoft.com/en-us/library/ms178592.aspx" rel="noreferrer"> raiserror método

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

Isto irá terminar a ligação, parando assim o resto do script de execução.

Note que tanto o nível de gravidade 20 ou superior e a opção WITH LOG são necessários para que ele funcione desta forma.

Isso funciona mesmo com as declarações GO, por exemplo.

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

Vamos dar-lhe a saída:

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.

Observe que 'ho' não é impresso.

Advertências:

  • Isso só funciona se você estiver logado como administrador (função 'sysadmin'), e também deixa você com nenhuma conexão de banco de dados.
  • Se você não estiver logado como administrador, o RAISEERROR () chamar-se falhará eo script vai continuar a executar .
  • Quando invocado com sqlcmd.exe, código de saída 2745 será relatado.

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

O método noexec

Outro método que funciona com declarações GO é set noexec on. Isso faz com que o resto do script a ser pulado. Ele não terminar a ligação, mas você precisa para transformar noexec novamente antes de quaisquer comandos será executado.

Exemplo:

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.

Outras dicas

Basta usar um RETURN (que vai funcionar tanto dentro como fora um procedimento armazenado).

Se você pode usar o modo SQLCMD, então o encantamento

:on error exit

(incluindo o cólon) fará com RAISERROR para realmente parar o script. Por exemplo.,

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

saída será:

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

e o lote vai parar. Se o modo SQLCMD não estiver ligado, você poderá obter um erro de interpretação sobre o cólon. Unfortuantely, não é completamente à prova de balas como se o script é executado sem ser no modo SQLCMD, SQL Managment Estúdio brisa passado certo até mesmo erros tempo de análise! Ainda assim, se você estiver executando-os na linha de comando, isso é bom.

Eu não usaria RAISERROR- SQL tem se as declarações que podem ser usados ??para este fim. Faça a sua validação e pesquisas e definir variáveis ??locais, em seguida, usar o valor das variáveis ??em instruções IF para fazer as inserções condicional.

Você não precisa verificar um resultado variável de todos os testes de validação. Você normalmente pode fazer isso com apenas uma variável de sinalizador para confirmar todas as condições passadas:

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

Mesmo que a sua validação é mais complexa, você deve só precisa de algumas variáveis ??bandeira de incluir na sua verificação final (s).

Eu estendi a noexec on / off solução sucesso com uma transação para executar o script de forma tudo ou nada.

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

Aparentemente o compilador "entende" a variável @finished no IF, mesmo se houve um erro e a execução foi desativado. No entanto, o valor é definido como 1 somente se a execução não foi desativado. Assim eu posso muito bem confirmar ou reverter a transação em conformidade.

Você poderia envolver a instrução SQL em um loop while e usar break se necessário

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

No SQL 2012+, você pode usar LANCE .

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

De MSDN:

gera uma exceção e transfere a execução de um bloco CATCH de uma construção try ... catch ... Se uma construção TRY ... CATCH não está disponível, a sessão é encerrada. O número da linha e processo em que a excepção é aumentada são definidas. A gravidade está definido para 16.

Este é um procedimento armazenado? Se assim for, eu acho que você poderia apenas fazer um retorno, como "Return NULL";

Além disso refinig método Sglasses, as linhas acima forçar o uso do modo SQLCMD, e quer treminates o scirpt se não estiver usando o modo SQLCMD ou usos :on error exit para sair em qualquer erro
CONTEXT_INFO é usado para manter o controle do Estado.

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

Gostaria de sugerir que você enrolar o seu bloco de código apropriado em um bloco try catch. então você pode usar o evento RAISERROR com uma gravidade de 11, a fim de quebrar o bloco catch, se desejar. Se você quiser apenas para raiserrors mas continuar a execução dentro do bloco try, em seguida, usar uma gravidade menor.

faz sentido?

Cheers, John

[Editado para incluir BOL Referência]

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

Você pode alterar o fluxo de execução usando GOTO declarações:

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

/* our code */

EndScript:

Você pode usar RAISERROR .

Nenhum desses trabalhos com declarações 'ir'. Neste código, independentemente da gravidade é 10 ou 11, você recebe a instrução PRINT final.

Script de Teste:

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

Resultados:

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

A única maneira de fazer este trabalho é escrever o script sem declarações GO. Às vezes, isso é fácil. Às vezes é muito difícil. (Use algo como IF @error <> 0 BEGIN ....)

Esta foi a minha solução:

...

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

Você pode usar instrução GOTO. Tente isto. Esta é a plena utilização para você.

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

FinalStatement:
     Select @CoumnName from TableName

Eu uso RETURN aqui o tempo todo, trabalha no script ou Stored Procedure

Certifique-se de ROLLBACK a transação se você estiver em um, caso contrário RETURN imediatamente resultará em uma transação não confirmada aberta

Thx para a resposta!

raiserror() funciona bem, mas você não deve esquecer a declaração return caso contrário o script continua sem erro! (Hense o raiserror não é um "throwError" ;-)) e, claro, fazer um rollback se necessário!

raiserror() é bom para dizer a pessoa que executa o script que algo deu errado.

Se você está simplesmente executar um script no Management Studio, e quer a execução parada ou operação de reversão (se usado) no primeiro erro, então a melhor maneira eu acho é usar blocos try catch (SQL 2005 em diante). Isso funciona bem no estúdio de gerenciamento se você estiver executando um arquivo script. proc armazenados sempre pode usar isso também.

De volta ao dia, utilizamos o seguinte ... funcionou melhor:

RAISERROR ('Error! Connection dead', 20, 127) WITH LOG
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top