web-dev-qa-db-fra.com

Boucle SQL pendant la pause

Dans une procédure stockée SQL Server 2012, j'ai plusieurs structures imbriquées. Je veux sortir d'une seule couche d'entre eux.

Je pensais que la description de BREAK dans le msdn https://msdn.Microsoft.com/en-CA/library/ms181271.aspx était de mon côté. Mais j'obtiens un comportement étrange en l'exécutant en une seule étape via le débogage. Je dis étrange parce que ce n'est pas cohérent. Parfois, il échappe à la couche que je m'attends .. parfois, il saute un couple.

WHILE ... BEGIN
  stuff1
  IF...BEGIN
    stuff2
    WHILE ... BEGIN
      stuff3
      IF .... BEGIN
        stuff4
        IF @NumberRecords=0 BREAK
        stuff5
      END
      --stuff6
      if @NumberRecords=0 and @loopBOMRowCount=@ResultsSOloopstart-1 break
      --on the last occasion I observed, @loopBOMRowCount was 6 and @ResultsSOloopstart 71 and it never highlighted this section, either way

      SET @loopBOMRowCount = @loopBOMRowCount + 1
    END
    stuff7 --nothing actually here
  END
  --stuff8
  SET @periodloopcount=@periodloopcount+1 
  --this is where it ended up highlighting on that last occasion
END
stuff9

Donc, si NumberRecords = 0, alors la prochaine opération devrait être la suivante: if at stuff6, non? Même si stuff4 inclut, par exemple, une table INSERT INTO d'un appel EXEC à une procédure stockée? Rien ne devrait pouvoir confondre la pile de ses couches?

Et oui, je réalise que c'est du vilain SQL. La plupart des instructions sont des modifications sur deux tables temporaires et j'évitais de les transmettre à des procédures stockées qui autrement nettoieraient le code.

EDIT

J'ai réussi à le faire passer comme je le voulais en ajoutant une boucle WHILE factice autour du SI intérieur, je veux commencer par le premier. Mais j'aimerais vraiment savoir comment j'interprète mal l'info msdn. Il semble dire qu'une pause doit sortir d'un SI, à condition qu'elle contienne une instruction END.

Sorties la boucle la plus interne dans une instruction WHILE ou une instruction IF… ELSE dans une boucle WHILE. Toutes les instructions apparaissant après le mot clé END, marquant la fin de la boucle, sont exécutées.

8
Hsmith

Je conviens que la documentation est un peu déroutante. Cette ligne semble suggérer que vous pouvez SORTIR d’un IF.

Quitte la boucle la plus interne dans une instruction WHILE ou une instruction IF… ELSE dans une boucle WHILE. Toutes les instructions apparaissant après le mot clé END, marquant la fin de la boucle, sont exécutées. BREAK est fréquemment, mais pas toujours, démarré par un test IF.

Cependant, ce n'est pas le cas. BREAK quitte le plus intérieur de sa position. La partie clé de la documentation est "toutes les instructions apparaissant après le mot-clé FIN, marquant la fin de la boucle , sont exécutées".

Cet exemple montre cela.

Exemple 1

DECLARE @X INT = 1;

PRINT 'Start'

/* WHILE loop required to use BREAK.
 */
WHILE @X = 1
BEGIN

    /* Outer IF.
     */
    IF 1 = 1 
    BEGIN
        /* Inner IF.
         */
        IF 2 = 2
        BEGIN
            BREAK
            PRINT '2'
        END

        PRINT '1'
    END

    SET @X = @X + 1;
END

PRINT 'End'

Seul le texte de début et de fin est imprimé. 1 n'est pas imprimé parce que BREAK existe et WHILE.

Vous pouvez également voir ce comportement ici:

Exemple 2

/* Anti-Pattern.
 * Breaking outside a WHILE is not allowed.
 */
IF 1 = 1 
BEGIN
    BREAK 
    PRINT 1
END

Cette requête renvoie l'erreur:

Msg 135, niveau 15, état 1, ligne 4 Impossible d'utiliser une instruction BREAK en dehors du cadre d'une instruction WHILE.

6
destination-data

Si vous voulez vraiment vous échapper de la déclaration SI, imprimez "Démarrer, 1, Fin" comme dans l'exemple ci-dessus, procédez comme suit:

DECLARE @X INT = 1;

PRINT 'Start'

/* WHILE loop required to use BREAK.
 */
WHILE @X = 1
BEGIN

    /* Outer IF.
     */
    IF 1 = 1 
    BEGIN
        /* Inner IF.
         */
        IF 2 = 2
        BEGIN
            GOTO skip2
            PRINT '2'
        END
        skip2:

        PRINT '1'
    END

    SET @X = @X + 1;
END

PRINT 'End'

Maintenant, alors que vous pourriez utiliser cela pour gérer l'exemple du PO en utilisant ce qui suit

WHILE ... BEGIN
  stuff1
  IF...BEGIN
    stuff2
    WHILE ... BEGIN
      stuff3
      IF .... BEGIN
        stuff4
        IF @NumberRecords=0
            GOTO startstuff6
        stuff5
      END
      startstuff6:
      --stuff6
      if @NumberRecords=0 and @loopBOMRowCount=@ResultsSOloopstart-1
        GOTO startstuff7
      --on the last occasion I observed, @loopBOMRowCount was 6 and @ResultsSOloopstart 71 and it never highlighted this section, either way

      SET @loopBOMRowCount = @loopBOMRowCount + 1
    END
    startstuff7:
    stuff7 --nothing actually here
  END
  --stuff8
  SET @periodloopcount=@periodloopcount+1 
  --this is where it ended up highlighting on that last occasion
END
stuff9

Il est généralement considéré comme une meilleure approche d'inverser votre logique booléenne, par exemple:

IF NOT @NumberRecords=0
BEGIN
        stuff5
END
0
Sean