Esegui il ciclo while in SQL Server 2008


120

Esiste un metodo per implementare il do whileloop in SQL Server 2008?


5
La risposta data da Rahul è corretta, ma cosa stai cercando di ottenere esattamente? I loop sono costosi rispetto alle soluzioni basate su set. Forse è possibile evitare del tutto un ciclo.
Lieven Keersmaekers

Non utilizzare i loop se possibile e stimerei che il 95% delle volte o più è possibile evitarli. Loop e cursori sono killer delle prestazioni e non dovrebbero mai essere scritti da chiunque non sia un amministratore di database esperto con almeno cinque anni di ottimizzazione delle prestazioni.
HLGEM

1
Er. leggermente drammatico lì HLGEM, i loop e i cursori sono in realtà abbastanza puliti fintanto che non stai ripetendo ogni riga in una tabella. Se hai un elenco di categorie o siti o qualcosa di relativamente alto livello, un ciclo potrebbe essere il modo più efficiente per eseguire la tua query.
Geoff Griswald

Risposte:


190

Non sono sicuro di DO-WHILE IN MS SQL Server 2008 ma puoi cambiare la logica del tuo ciclo WHILE, in modo da USARE come il ciclo DO-WHILE.

Gli esempi sono presi da qui: http://blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of-while-loop-with-continue-and-break-keywords/

  1. Esempio di WHILE Loop

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
    END
    GO

    ResultSet:

    1
    2
    3
    4
    5
  2. Esempio di ciclo WHILE con parola chiave BREAK

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
        IF @intFlag = 4
            BREAK;
    END
    GO

    ResultSet:

    1
    2
    3
  3. Esempio di ciclo WHILE con le parole chiave CONTINUE e BREAK

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
        CONTINUE;
        IF @intFlag = 4 -- This will never executed
            BREAK;
    END
    GO

    ResultSet:

    1
    2
    3
    4
    5

Ma cerca di evitare loop a livello di database. Riferimento .


17
Gli stessi esempi sono riportati qui, sei l'autore di questo sito? blog.sqlauthority.com/2007/10/24/…
anar khalilov

1
Non lo è, ma perché è importante? È stata data la risposta corretta. Il collegamento a un altro sito Web è una seccatura, copiare e incollare la risposta qui è utile.
Geoff Griswald

61

Se non sei molto offeso dalla GOTOparola chiave, può essere utilizzata per simulare un DO/ WHILEin T-SQL. Considera il seguente esempio piuttosto privo di senso scritto in pseudocodice:

SET I=1
DO
 PRINT I
 SET I=I+1
WHILE I<=10

Ecco il codice T-SQL equivalente che utilizza goto:

DECLARE @I INT=1;
START:                -- DO
  PRINT @I;
  SET @I+=1;
IF @I<=10 GOTO START; -- WHILE @I<=10

Notare la mappatura uno a uno tra la GOTOsoluzione abilitata e l'originale DO/ WHILEpseudocodice. Un'implementazione simile che utilizza un WHILEciclo sarebbe simile a:

DECLARE @I INT=1;
WHILE (1=1)              -- DO
 BEGIN
  PRINT @I;
  SET @I+=1;
  IF NOT (@I<=10) BREAK; -- WHILE @I<=10
 END

Ora, potresti ovviamente riscrivere questo particolare esempio come un semplice WHILEciclo, poiché questo non è un buon candidato per un costrutto DO/ WHILE. L'enfasi era sulla brevità dell'esempio piuttosto che sull'applicabilità, poiché i casi legittimi che richiedono una DO/ WHILEsono rari.


REPEAT / UNTIL, chiunque (NON funziona in T-SQL)?

SET I=1
REPEAT
  PRINT I
  SET I=I+1
UNTIL I>10

... e la GOTOsoluzione basata in T-SQL:

DECLARE @I INT=1;
START:                    -- REPEAT
  PRINT @I;
  SET @I+=1;
IF NOT(@I>10) GOTO START; -- UNTIL @I>10

Attraverso l'uso creativo GOTOe l'inversione logica tramite la NOTparola chiave, esiste una relazione molto stretta tra lo pseudocodice originale e la GOTOsoluzione basata. Una soluzione simile che utilizza un WHILEciclo ha il seguente aspetto:

DECLARE @I INT=1;
WHILE (1=1)       -- REPEAT
 BEGIN
  PRINT @I;
  SET @I+=1;
  IF @I>10 BREAK; -- UNTIL @I>10
 END

Si può argomentare che per il caso della REPEAT/ UNTIL, laWHILE soluzione basata è più semplice, perché la condizione if non è invertita. D'altra parte è anche più prolisso.

Se non fosse per tutto il disprezzo sull'uso di GOTO , queste potrebbero anche essere soluzioni idiomatiche per quelle poche volte in cui questi particolari costrutti (malvagi) di loop sono necessari nel codice T-SQL per motivi di chiarezza.

Usali a tua discrezione, cercando di non subire l'ira dei tuoi colleghi sviluppatori quando ti sorprendono a usare il tanto diffamato GOTO.


6
+1: risponde decisamente alla domanda meglio della risposta accettata.
Louis Kottmann

Preferisco l'approccio WHILE (1 = 1), poiché si adatta funzionalmente allo scopo senza utilizzare il temuto GOTO.
kad81

Entrambi i metodi sono validi. Mi piace lo pseudo-loop usando GOTO, è abbastanza intelligente.
Geoff Griswald

18

Mi sembra di ricordare di aver letto questo articolo più di una volta e la risposta è vicina a ciò di cui ho bisogno.

Di solito quando penso che avrò bisogno di un DO WHILEin T-SQL è perché sto iterando un cursore e cerco in gran parte una chiarezza ottimale (rispetto alla velocità ottimale). In T-SQL che sembra adattarsi a WHILE TRUE/ IF BREAK.

Se questo è lo scenario che ti ha portato qui, questo frammento potrebbe farti risparmiare un momento. Altrimenti, bentornato, me. Ora posso essere certo di essere stato qui più di una volta. :)

DECLARE Id INT, @Title VARCHAR(50)
DECLARE Iterator CURSOR FORWARD_ONLY FOR
SELECT Id, Title FROM dbo.SourceTable
OPEN Iterator
WHILE 1=1 BEGIN
    FETCH NEXT FROM @InputTable INTO @Id, @Title
    IF @@FETCH_STATUS < 0 BREAK
    PRINT 'Do something with ' + @Title
END
CLOSE Iterator
DEALLOCATE Iterator

Sfortunatamente, T-SQL non sembra offrire un modo più pulito per definire singolarmente l'operazione di ciclo rispetto a questo ciclo infinito.


L'utilizzo di un cursore non è mai una buona opzione in quanto richiede molte più risorse di quelle effettivamente necessarie.
greektreat

10
@greektreat: grazie per il voto negativo :), ma sono confuso! Se "un cursore non è mai una buona opzione", allora deve sempre essere una buona opzione, quindi perché il voto negativo? Scherzi a parte, però, ovviamente i cursori hanno molti usi abbastanza pratici: contro tabelle private, per piccole operazioni dove chiarezza / brevità> prestazioni, per attività di manutenzione, dove non sono disponibili operazioni deterministiche, per certe operazioni devono avvenire come una transazione atomica a prescindere, ecc. Nel mio caso recente, stavo importando una variabile di tabella in entrata, privata nella mia procedura memorizzata. Una banalità assoluta non è mai una buona idea!
Shannon

5
@greektreat: in sintesi, a volte l'iterazione dei dati è l'UNICA opzione. Suppongo che potresti ancora sostenere che non è una buona opzione in quel caso, ma ciò non significa che questo tipo di codice non sia necessario e abbia bisogno di downvote.
Shannon

1
Penso che ci sia un esercito rabbioso di persone su Internet che sono molto, molto arrabbiate per le altre persone che usano loop e cursori in SQL. Su questo sito web, se anche solo menzionate l'utilizzo di un ciclo in SQL circa 30 secondi dopo, la vostra casella di posta sarà invasa da persone ignoranti che vi dicono di non usarli in QUALSIASI circostanza ...
Geoff Griswald

4

Puoi anche usare una variabile di uscita se vuoi che il tuo codice sia un po 'più leggibile:

DECLARE @Flag int = 0
DECLARE @Done bit = 0

WHILE @Done = 0 BEGIN
    SET @Flag = @Flag + 1
    PRINT @Flag
    IF @Flag >= 5 SET @Done = 1
END

Questo sarebbe probabilmente più rilevante quando hai un ciclo più complicato e stai cercando di tenere traccia della logica. Come affermato, i loop sono costosi, quindi cerca di utilizzare altri metodi se puoi.


Voglio dire ... Viviamo in un'epoca in cui i nostri server database hanno da 10 a 20 core CPU inattivi in ​​un dato momento e in cui i nostri controller di archiviazione hanno la larghezza di banda disponibile misurata in Gigabit, quindi non sono sicuro che sia convenzionale " saggezza "che" LOOP = BAD "si applica ancora.
Geoff Griswald

1

Solo While Loop è ufficialmente supportato dal server SQL. C'è già una risposta per DO while loop. Sto descrivendo in dettaglio la risposta sui modi per ottenere diversi tipi di loop nel server SQL.

Se lo sai, devi comunque completare la prima iterazione del ciclo, quindi puoi provare DO..WHILE o REPEAT..UNTIL versione di SQL server.

DO..WHILE Loop

DECLARE @X INT=1;

WAY:  --> Here the  DO statement

  PRINT @X;

  SET @X += 1;

IF @X<=10 GOTO WAY;

REPEAT..UNTIL Loop

DECLARE @X INT = 1;

WAY:  -- Here the REPEAT statement

  PRINT @X;

  SET @X += 1;

IFNOT(@X > 10) GOTO WAY;

FOR Loop

DECLARE @cnt INT = 0;

WHILE @cnt < 10
BEGIN
   PRINT 'Inside FOR LOOP';
   SET @cnt = @cnt + 1;
END;

PRINT 'Done FOR LOOP';

Riferimento


Sembra un riordino copia-incolla da stackoverflow.com/a/46362450/8239061 .
SecretAgentMan

@SecretAgentMan: entrambe le risposte rispondono a domande diverse. Dati aggiuntivi forniti in entrambe le risposte.
Somnath Muluk
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.