Do while-Schleife in SQL Server 2008

120

Gibt es eine Methode zum Implementieren einer do whileSchleife in SQL Server 2008?

Nithesh Narayanan
quelle
5
Die Antwort von Rahul ist richtig, aber was genau versuchen Sie zu erreichen? Schleifen sind im Vergleich zu satzbasierten Lösungen teuer. Vielleicht ist es möglich, eine Schleife ganz zu vermeiden.
Lieven Keersmaekers
Verwenden Sie nach Möglichkeit keine Schleifen, und ich würde schätzen, dass es in 95% der Fälle oder mehr möglich ist, diese zu vermeiden. Loops und Cursor sind Performance-Killer und sollten niemals von jemandem geschrieben werden, der kein erfahrener DBA mit mindestens fünfjähriger Performance-Optimierung ist.
HLGEM
1
Er. etwas dramatisch dort HLGEM, Schleifen und Cursor sind eigentlich ziemlich ordentlich, solange Sie nicht jede Zeile in einer Tabelle durchlaufen. Wenn Sie eine Liste von Kategorien oder Websites oder etwas relativ Hochrangiges haben, ist eine Schleife möglicherweise die effizienteste Methode, um Ihre Abfrage auszuführen.
Geoff Griswald

Antworten:

190

Ich bin mir bei DO-WHILE in MS SQL Server 2008 nicht sicher, aber Sie können Ihre WHILE-Schleifenlogik ändern, um sie wie die DO-WHILE-Schleife zu verwenden.

Beispiele finden Sie hier: http://blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of-while-loop-with-continue-and-break-keywords/

  1. Beispiel für eine WHILE-Schleife

    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. Beispiel für eine WHILE-Schleife mit dem Schlüsselwort 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. Beispiel für eine WHILE-Schleife mit den Schlüsselwörtern CONTINUE und 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

Aber versuchen, Schleifen zu vermeiden auf Datenbankebene. Referenz .

Pratik
quelle
17
Die gleichen Beispiele finden Sie hier. Sind Sie der Autor dieser Website? blog.sqlauthority.com/2007/10/24/…
anar khalilov
1
Er ist nicht, aber warum ist es wichtig? Die richtige Antwort wurde gegeben. Das Verknüpfen mit einer anderen Website ist mühsam. Das Kopieren und Einfügen der Antwort hier ist hilfreich.
Geoff Griswald
61

Wenn Sie mit dem GOTOSchlüsselwort nicht sehr beleidigt sind , können Sie damit ein DO/ WHILEin T-SQL simulieren . Betrachten Sie das folgende eher unsinnige Beispiel, das in Pseudocode geschrieben ist:

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

Hier ist der äquivalente T-SQL-Code mit goto:

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

Beachten Sie die Eins-zu-Eins-Zuordnung zwischen der GOTOaktivierten Lösung und dem Original DO/ WHILEPseudocode. Eine ähnliche Implementierung mit einer WHILESchleife würde folgendermaßen aussehen:

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

Jetzt können Sie dieses Beispiel natürlich als einfache WHILESchleife umschreiben , da dies kein so guter Kandidat für ein DO/ WHILE-Konstrukt ist. Der Schwerpunkt lag eher auf der Kürze des Beispiels als auf der Anwendbarkeit, da legitime Fälle, die ein DO/ erfordern, WHILEselten sind.


REPEAT / UNTIL, jemand (funktioniert NICHT in T-SQL)?

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

... und die GOTObasierte Lösung in T-SQL:

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

Durch die kreative Verwendung GOTOund logische Inversion über das NOTSchlüsselwort besteht eine sehr enge Beziehung zwischen dem ursprünglichen Pseudocode und der GOTObasierten Lösung. Eine ähnliche Lösung mit einer WHILESchleife sieht folgendermaßen aus:

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

Es kann argumentiert werden, dass für den Fall von REPEAT/ UNTILdie WHILEbasierte Lösung einfacher ist, da die if-Bedingung nicht invertiert wird. Andererseits ist es auch ausführlicher.

Wenn nicht all die Verachtung in Bezug auf die Verwendung von wäre GOTO, könnten dies sogar idiomatische Lösungen für die wenigen Male sein, in denen diese speziellen (bösen) Schleifenkonstrukte aus Gründen der Klarheit im T-SQL-Code erforderlich sind.

Verwenden Sie diese nach eigenem Ermessen und versuchen Sie, nicht den Zorn Ihrer Entwicklerkollegen zu erleiden, wenn sie Sie mit den vielfach bösartigen Personen erwischen GOTO.

Michael Goldshteyn
quelle
6
+1: Beantwortet die Frage definitiv besser als die akzeptierte Antwort.
Louis Kottmann
Ich bevorzuge den WHILE-Ansatz (1 = 1), da er funktional dem Zweck entspricht, ohne das gefürchtete GOTO zu verwenden.
Kad81
Beide Methoden sind gültig. Ich mag die Pseudo-Schleife mit GOTO, sie ist ziemlich clever.
Geoff Griswald
18

Ich erinnere mich an das mehrmalige Lesen dieses Artikels, und die Antwort kommt nur dem nahe , was ich brauche.

Wenn ich denke, dass ich einen DO WHILEin T-SQL benötige, liegt das normalerweise daran, dass ich einen Cursor iteriere und hauptsächlich nach optimaler Klarheit (im Vergleich zu optimaler Geschwindigkeit) suche. In T-SQL scheint das zu einem WHILE TRUE/ zu passen IF BREAK.

Wenn dies das Szenario ist, das Sie hierher gebracht hat, kann dieses Snippet Ihnen einen Moment ersparen. Ansonsten willkommen zurück, ich. Jetzt kann ich sicher sein, dass ich mehr als einmal hier war. :) :)

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

Leider scheint T-SQL keine sauberere Möglichkeit zu bieten, die Schleifenoperation einzeln zu definieren, als diese Endlosschleife.

Shannon
quelle
Die Verwendung eines Cursors ist niemals keine gute Option, da viel mehr Ressourcen benötigt werden, als tatsächlich benötigt werden.
Greektreat
10
@greektreat: Danke für die Ablehnung :), aber ich bin verwirrt! Wenn "ein Cursor niemals keine gute Option ist", muss es immer eine gute Option sein. Warum also die Abwertung? Im Ernst, Cursor haben offensichtlich viele praktische Anwendungen: gegen private Tabellen, für kleine Operationen, bei denen Klarheit / Kürze> Leistung, für Wartungsaufgaben, bei denen keine deterministischen Operationen verfügbar sind, für bestimmte Operationen müssen unabhängig davon als atomare Transaktion ausgeführt werden usw. In meinem letzten Fall habe ich eine eingehende Tabellenvariable aufgenommen, die für meine gespeicherte Prozedur privat ist. Eine absolute Plattheit ist niemals eine gute Idee!
Shannon
5
@greektreat: Zusammenfassend ist manchmal das Iterieren von Daten die EINZIGE Option. Ich nehme an, Sie könnten immer noch argumentieren, dass dies in diesem Fall keine gute Option ist, aber das bedeutet nicht, dass diese Art von Code unnötig ist und eine Abstimmung erfordert.
Shannon
1
Ich denke, es gibt eine tollwütige Armee von Leuten im Internet, die sehr, sehr wütend auf andere Leute sind, die Schleifen und Cursor in SQL verwenden. Wenn Sie auf dieser Website etwa 30 Sekunden später sogar die Verwendung einer Schleife in SQL erwähnen, wird Ihr Posteingang von unwissenden Personen überflutet, die Ihnen sagen, dass Sie sie unter KEINEN Umständen verwenden sollen ...
Geoff Griswald
4

Sie können auch eine Exit-Variable verwenden, wenn Ihr Code besser lesbar sein soll:

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

Dies wäre wahrscheinlich relevanter, wenn Sie eine kompliziertere Schleife haben und versuchen, die Logik im Auge zu behalten. Wie bereits erwähnt, sind Schleifen teuer. Versuchen Sie daher, andere Methoden zu verwenden, wenn Sie können.

Sebris87
quelle
Ich meine ... Wir leben in einer Zeit, in der unsere Datenbankserver zu einem bestimmten Zeitpunkt zwischen 10 und 20 CPU-Kerne im Leerlauf haben und in der die verfügbare Bandbreite unserer Speichercontroller in Gigabit gemessen wird. Ich bin mir also nicht sicher, ob dies konventionell ist. " Weisheit ", dass" LOOP = BAD "noch gilt.
Geoff Griswald
1

Nur While Loop wird offiziell vom SQL Server unterstützt. Es gibt bereits eine Antwort für DO while-Schleife. Ich erläutere die Antwort auf Möglichkeiten, um verschiedene Arten von Schleifen in SQL Server zu erreichen.

Wenn Sie wissen, dass Sie die erste Iteration der Schleife trotzdem abschließen müssen, können Sie die Version DO..WHILE oder REPEAT..UNTIL von SQL Server ausprobieren .

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

DECLARE @cnt INT = 0;

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

PRINT 'Done FOR LOOP';

Referenz

Somnath Muluk
quelle
Dies scheint eine Kopier - Einfüge -Neuordnung von stackoverflow.com/a/46362450/8239061 zu sein .
SecretAgentMan
@SecretAgentMan: Beide Antworten beantworten unterschiedliche Fragen. Zusätzliche Daten in beiden Antworten.
Somnath Muluk