web-dev-qa-db-fra.com

Commande T-SQL STOP ou ABORT dans SQL Server

Existe-t-il une commande dans Microsoft SQL Server T-SQL pour indiquer au script d'arrêter le traitement? J'ai un script que je souhaite conserver à des fins d'archivage, mais je ne veux pas que quiconque l'exécute.

50
Phillip Senn

Une autre solution pourrait être de modifier le flux d'exécution de votre script en utilisant l'instruction GOTO ...

DECLARE  @RunScript bit;
SET @RunScript = 0;

IF @RunScript != 1
BEGIN
RAISERROR ('Raise Error does not stop processing, so we will call GOTO to skip over the script', 1, 1);
GOTO Skipper -- This will skip over the script and go to Skipper
END

PRINT 'This is where your working script can go';
PRINT 'This is where your working script can go';
PRINT 'This is where your working script can go';
PRINT 'This is where your working script can go';

Skipper: -- Don't do nuttin!

Attention! L'échantillon ci-dessus est dérivé d'un exemple que j'ai obtenu de Merrill Aldrich. Avant d'implémenter aveuglément l'instruction GOTO, je vous recommande de lire son tutoriel sur Contrôle de flux dans les scripts T-SQL .

45
Jed

Non, il n'y en a pas - vous avez deux options:

  1. Enveloppez le script entier dans un grand bloc if/end qui est simplement garanti de ne pas être vrai (c'est-à-dire "si 1 = 2 commence" - cela ne fonctionnera cependant que si le script ne comprend aucune instruction GO (car celles-ci indiquent un nouveau lot)

  2. Utilisez l'instruction de retour en haut (là encore, limitée par les séparateurs de lots)

  3. Utilisez une approche basée sur la connexion, qui garantira la non-exécution de l'ensemble du script (toute la connexion pour être plus précis) - utilisez quelque chose comme 'SET PARSEONLY ON' ou 'SET NOEXEC ON ' en haut du script. Cela garantira que toutes les instructions dans la connexion (ou jusqu'à ce que ladite instruction set soit désactivée) ne s'exécutent pas et seront à la place analysées/compilées uniquement.

  4. Utilisez un bloc de commentaires pour commenter l'intégralité du script (c'est-à-dire/* et * /)

EDIT: Démonstration que l'instruction 'return' est spécifique au lot - notez que vous continuerez à voir les jeux de résultats après les retours:

select 1
return
go
select 2
return
select 3
go
select 4
return
select 5
select 6
go
36
boydc7

Pourquoi ne pas simplement ajouter ce qui suit au début du script

PRINT 'INACTIVE SCRIPT'
RETURN
17
Sparky

Pour contourner le problème RETURN/GO, vous pouvez placer RAISERROR ('Oi! Stop!', 20, 1) WITH LOG en haut.

Cela fermera la connexion client selon RAISERROR sur MSDN .

Le très gros inconvénient est que vous devez être administrateur système pour utiliser la gravité 20.

Modifier:

Une simple démonstration pour contrer le commentaire de Jersey Dude ...

RAISERROR ('Oi! Stop!', 20, 1)  WITH LOG
SELECT 'Will not run'
GO
SELECT 'Will not run'
GO
SELECT 'Will not run'
GO
14
gbn

RAISERROR de gravité 20 sera signalé comme une erreur dans l'Observateur d'événements.

Vous pouvez utiliser SET PARSEONLY ON; (ou NOEXEC). À la fin du script, utilisez GO SET PARSEONLY OFF;

SET PARSEONLY ON;
-- statement between here will not run

SELECT 'THIS WILL NOT EXEC';

GO
-- statement below here will run

SET PARSEONLY OFF;

Essayez de l'exécuter en tant que script TSQL

SELECT 1
RETURN
SELECT 2
SELECT 3

Le retour met fin à l'exécution.

RETOUR (Transact-SQL)

Quitte inconditionnellement une requête ou une procédure. RETURN est immédiat et complet et peut être utilisé à tout moment pour quitter une procédure, un lot ou un bloc d'instructions. Les instructions qui suivent RETURN ne sont pas exécutées.

3
Adriaan Stander

Voici une façon quelque peu délicate de le faire qui fonctionne avec des lots GO, en utilisant une variable "globale".

if object_id('tempdb..#vars') is not null
begin
  drop table #vars
end

create table #vars (continueScript bit)
set nocount on
  insert #vars values (1)
set nocount off

-- Start of first batch
if ((select continueScript from #vars)=1) begin

  print '1'

  -- Conditionally terminate entire script
  if (1=1) begin
    set nocount on
      update #vars set continueScript=0
    set nocount off
    return
  end

end
go

-- Start of second batch
if ((select continueScript from #vars)=1) begin

  print '2'

end
go

Et voici la même idée utilisée avec une transaction et un bloc try/catch pour chaque GO-batch. Vous pouvez essayer de changer les différentes conditions et/ou le laisser générer une erreur (diviser par 0, voir commentaires) pour tester son comportement:

if object_id('tempdb..#vars') is not null
begin
  drop table #vars
end

create table #vars (continueScript bit)
set nocount on
  insert #vars values (1)
set nocount off

begin transaction;
  -- Batch 1 starts here
  if ((select continueScript from #vars)=1) begin
    begin try 
      print 'batch 1 starts'

      if (1=0) begin
        print 'Script is terminating because of special condition 1.'
        set nocount on
          update #vars set continueScript=0
        set nocount off
        return
      end

      print 'batch 1 in the middle of its progress'

      if (1=0) begin
        print 'Script is terminating because of special condition 2.'
        set nocount on
          update #vars set continueScript=0
        set nocount off
        return
      end

      set nocount on
        -- use 1/0 to generate an exception here
        select 1/1 as test
      set nocount off

    end try
    begin catch
      set nocount on
        select 
          error_number() as errornumber
          ,error_severity() as errorseverity
          ,error_state() as errorstate
          ,error_procedure() as errorprocedure
          ,error_line() as errorline
          ,error_message() as errormessage;
        print 'Script is terminating because of error.'
        update #vars set continueScript=0
      set nocount off
      return
    end catch;

  end
  go

  -- Batch 2 starts here
  if ((select continueScript from #vars)=1) begin

    begin try 
      print 'batch 2 starts'

      if (1=0) begin
        print 'Script is terminating because of special condition 1.'
        set nocount on
          update #vars set continueScript=0
        set nocount off
        return
      end

      print 'batch 2 in the middle of its progress'

      if (1=0) begin
        print 'Script is terminating because of special condition 2.'
        set nocount on
          update #vars set continueScript=0
        set nocount off
        return
      end

      set nocount on
        -- use 1/0 to generate an exception here
        select 1/1 as test
      set nocount off

    end try
    begin catch
      set nocount on
        select 
          error_number() as errornumber
          ,error_severity() as errorseverity
          ,error_state() as errorstate
          ,error_procedure() as errorprocedure
          ,error_line() as errorline
          ,error_message() as errormessage;
        print 'Script is terminating because of error.'
        update #vars set continueScript=0
      set nocount off
      return
    end catch;

  end
  go

if @@trancount > 0 begin
  if ((select continueScript from #vars)=1) begin
    commit transaction
    print 'transaction committed'
  end else begin
    rollback transaction;
    print 'transaction rolled back'
  end
end
3
Magnus

Malgré sa description très explicite et énergique, RETURN n'a pas fonctionné pour moi dans une procédure stockée (pour ignorer l'exécution ultérieure). J'ai dû modifier la logique des conditions. Se produit sur SQL 2008, 2008 R2:

create proc dbo.prSess_Ins
(
    @sSessID    varchar( 32 )
,   @idSess     int out
)
as
begin
    set nocount on

    select  @id=    idSess
        from    tbSess
        where   sSessID = @sSessID

    if  @idSess > 0 return  -- exit sproc here

    begin   tran
        insert  tbSess  ( sSessID ) values  ( @sSessID )
        select  @idSess=    scope_identity( )
    commit
end

devait être changé en:

    if  @idSess is null
    begin
        begin   tran
            insert  tbSess  ( sSessID ) values  ( @sSessID )
            select  @idSess=    scope_identity( )
        commit
    end

Découvert suite à la recherche de lignes dupliquées. Le débogage des PRINT a confirmé que @idSess avait une valeur supérieure à zéro dans la vérification IF - RETURN n'a pas interrompu l'exécution!

2
Astrogator

Je sais que la question est ancienne et a été répondue correctement de différentes manières, mais il n'y a pas de réponse comme la mienne que j'ai utilisée dans des situations similaires. Première approche (très basique):

IF (1=0)
BEGIN
    PRINT 'it will not go there'
    -- your script here
END
PRINT 'but it will here'

Deuxième approche:

PRINT 'stop here'
RETURN
    -- your script here
PRINT 'it will not go there'

Vous pouvez le tester facilement par vous-même pour vous assurer qu'il se comporte comme prévu.

1
Pawel Czapski