SQL Server: Como abortar uma série de lotes no analisador de consultas?
-
06-09-2019 - |
Pergunta
Eu tenho uma série de declarações T-SQL separadas pela palavra-chave de separador de lote do analisador de consulta especial:
GO
Se um lote falhar, preciso do analisador de consultas para não experimentar lotes subsequentes - quero que ele pare de processar a série de lotes.
Por exemplo:
PRINT 'This runs'
go
SELECT 0/0, 'This causes an error'
go
PRINT 'This should not run'
go
Resultado:
This runs
Server: Msg 8134, Level 16, State 1, Line 2
Divide by zero error encountered.
This should not run
Possível?
Atualizar
Um exemplo disso em uso real pode ser:
sp_rename 'Shelby', 'Kirsten'
go
DROP VIEW PeekAView
go
CREATE VIEW PeekAViewAS
SELECT * FROM Kirsten
go
Solução
Aqui está como eu faria isso:
PRINT 'This runs'
go
SELECT 0/0, 'This causes an error'
go
if (@@error <> 0)
Begin
set nocount on
set noexec on
End
GO
PRINT 'This should not run'
go
set noexec off
set nocount off
GO
O modo "NoEXEC" coloca o SSMS é um estado em que apenas compila o T-SQL e na verdade não o executa. É semelhante a pressionar acidentalmente o botão da barra de ferramentas de parse (Ctrl+F5) em vez de executar (F5).
Não se esqueça de desligar o Noexec no final do seu script. Caso contrário, os usuários ficarão confusos com os "comando (s) permanente (s) concluídos com êxito". mensagens.
Eu uso a verificação contra o erro @@ no lote subsequente, em vez de usar os blocos Try Catch. Usando o erro @@ no próximo lote, capturará erros de compilação, como "a tabela não existe".
Além do modo NOEXEC, também alterno o modo Nocount. Com o modo NoEXEC ON e NOCOUNT OFF, suas consultas ainda relatarão uma mensagem "(0 linhas (s) afetadas)". A mensagem sempre relata zero linhas, porque você está no modo NoExec. No entanto, transformar o Nocount em suprime essas mensagens.
Observe também que, se a execução do SQL Server 2005, o comando que você está pulando ainda poderá fornecer mensagens de erro se referir uma tabela que não existir e o comando se o primeiro comando no lote. Forçar o comando a ser o segundo comando no lote com uma declaração de impressão falsa pode suprimir isso. Ver MS Bug #569263 para mais detalhes.
Outras dicas
Você pode ativar a opção de menu "consulta, modo sqlcmd" e colocar o seguinte no início do script:
:on error exit
Isso interromperá a execução quando ocorrer um erro, mesmo que haja lotes subsequentes.
Apenas certifique -se de não executar acidentalmente o script sem o modo SQLCMD, porque você obterá o comportamento típico em que os erros são ignorados.
Quando preciso fazer isso, emite um Raiserror da gravidade 20. Isso, ou superior, matará a conexão atual e impedirá a execução de "lotes" subsequentes. Sim, pode ser estranho, mas faz o trabalho.
Criar uma tabela temporária; e atualize -o após cada etapa (se for bem -sucedido); e, em seguida, verifique o sucesso da etapa anterior, validando contra a tabela.
create table #ScriptChecker (SuccessfullStep int)
-- Do Step One
Insert into #ScriptChecker
Select 1
-- Step 2
If exists (select * from #ScriptChecker where SuccessfullStep = 1)
-- Do Step 2 ...
Baseado na ideia @u07ch, mas apenas insira o fracasso ...
create table #test (failure int)
if not exists (select * from #test)
BEGIN
print 'one' --sql here
END
go
if not exists (select * from #test)
BEGIN
print 'two'--sql here
END
go
if not exists (select * from #test)
BEGIN
print 'three' ---SQL SERVER 2000 version
--error--
SELECT 0/0, 'This causes an error'
IF @@ERROR!=0
BEGIN
insert into #test values (1)
PRINT 'ERROR'
END
end
go
if not exists (select * from #test)
BEGIN
print 'three' ---SQL SERVER 2005/2008 version
BEGIN TRY
--error--
SELECT 0/0, 'This causes an error'
END TRY
BEGIN CATCH
insert into #test values (1)
PRINT 'ERROR'
END CATCH
END
go
if not exists (select * from #test)
BEGIN
--sql here
print 'four'
END
go
Saída 2000:
one
two
three
----------- --------------------
Msg 8134, Level 16, State 1, Line 7
Divide by zero error encountered.
(1 row(s) affected)
ERROR
Saída 2005/2008:
one
two
three
----------- --------------------
(0 row(s) affected)
(1 row(s) affected)
ERROR
Erland Sommarskog no Microsoft.public.sqlserver.programing Group teve uma boa ideia:
Em um script de mudança como o que você postou, você precisa estar na defensiva e iniciar cada lote com se @@ trancount> 0.
Usando
IF @@trancount > 0
é muito mais limpo.