SQL Server 2008でwhileループを実行する


120

do whileSQL Server 2008でループを実装する方法はありますか?


5
ラフルの答えは正しいですが、正確に何を達成しようとしていますか?ループは、セットベースのソリューションと比較して高価です。おそらく、ループを完全に回避することが可能です。
Lieven Keersmaekers、2010

可能な限りループを使用しないでください。ループを回避できるのは95%以上の時間であると私は推定しています。ループとカーソルはパフォーマンスを大幅に低下させるものであり、5年以上のパフォーマンスチューニングの経験豊富なDBA以外の人が書いてはいけません。
HLGEM 2014

1
えー HLGEMはわずかに劇的ですが、テーブルのすべての行をループしない限り、ループとカーソルは実際には非常にきれいです。カテゴリやサイトのリスト、または比較的高いレベルのリストがある場合は、クエリを実行するための最も効率的な方法はループです。
Geoff Griswald、

回答:


190

MS SQL Server 2008のDO-WHILEについてはわかりませんが、DO-WHILEループのように使用できるように、WHILEループロジックを変更できます。

例はここから取得されます:http : //blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of-while-loop-with-continue-and-break-keywords/

  1. WHILEループの例

    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. BREAKキーワードを使用したWHILEループの例

    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. CONTINUEおよびBREAKキーワードを使用したWHILEループの例

    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
    

ただし、データベースレベルでのループ避けてください。 リファレンス


17
同じ例がここに示されています、あなたはこのウェブサイトの作者ですか?blog.sqlauthority.com/2007/10/24/...
anar khalilov

1
彼はそうではありませんが、なぜそれが重要なのですか?正解が出ました。別のウェブサイトにリンクするのは面倒です。ここに回答をコピーして貼り付けると便利です。
Geoff Griswald、

61

GOTOキーワードにあまり気分を害していない場合は、T-SQLでDO/ をシミュレートするために使用できWHILEます。疑似コードで書かれた次のどちらかといえば無意味な例を考えてみましょう。

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

gotoを使用した同等のT-SQLコードを次に示します。

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

GOTO有効なソリューションと元のDO/ WHILE疑似コード間の1対1のマッピングに注意してください。WHILEループを使用した同様の実装は次のようになります。

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

これはもちろん、この特定の例を単純なWHILEループとして書き直すこともできます。これは、DO/ WHILE構成にはあまり適していないためです。DO/ WHILEを必要とする正当なケースはまれであるため、適用可能性ではなく例を簡潔にすることに重点が置かれました。


REPEAT / UNTIL、誰か(T-SQLでは機能しません)?

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

... GOTOT-SQLのベースソリューション:

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

キーワードGOTOを使用した創造的な使用と論理反転NOTにより、元の疑似コードとGOTOベースのソリューションの間には非常に密接な関係があります。WHILEループを使用した同様のソリューションは次のようになります。

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

引数がある場合のために作製することができるREPEAT/ UNTILWHILEもし条件が反転していないので、ベースのソリューションは、簡単です。一方、それはまたより冗長です。

の使用に関する軽視のすべてがそうでなかった場合GOTO、これらの特定の(悪)ループ構造がT-SQLコードで明確にするために必要な場合は、これらが数回の慣例的な解決策になることもあります。

自分の裁量でこれらを使用し、悪意のあるユーザーがあなたを捕まえたときに他の開発者の怒りを被らないようにしてくださいGOTO


6
+1:間違いなく、受け入れられた回答よりもよく質問に回答します。
Louis Kottmann 2012

私はWHILE(1 = 1)アプローチを好みます。恐ろしいGOTOを使用せずに目的に機能的に適合するためです。
kad81 2017年

どちらの方法も有効です。GOTOを使用した疑似ループが好きです。とても賢いです。
ジェフグリスワルド

18

私はこの記事を何度も読んだことを思い出しているようで、答えは私が必要としているものに近いだけです。

通常DO WHILE、T-SQLでが必要になると思うのは、カーソルを反復しているためです。最適な明快さ(最適速度と比べて)を主に探しています。T-SQLではWHILE TRUE/ に合うようIF BREAKです。

それがここにあなたを連れてきたシナリオであるなら、このスニペットはあなたを一瞬節約するかもしれません。そうでなければ、おかえりなさい、私。これで、ここに2度以上来たことがあると確信できます。:)

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

残念ながら、T-SQLは、この無限ループよりも、ループ操作を単独で定義するためのより明確な方法を提供していないようです。


Cursorを使用することは、実際に必要なより多くのリソースを必要とするため、決して良い選択肢ではありません。
ギリシャの治療2014年

10
@greektreat:反対投票に感謝します:)しかし、私は混乱しています!「カーソルが決して良いオプションではない」場合、それは常に良いオプションでなければならないのに、なぜ反対票か。しかし真剣に、カーソルは明らかに実用的な多くの用途を持っています:プライベートテーブルに対して、明確性/簡潔さ>パフォーマンスである小さな操作の場合、メンテナンスタスク、決定論的な操作が利用できない場合、特定の操作はアトミックトランザクションとして発生する必要がありますなど。私の最近のケースでは、私は自分のストアドプロシージャにプライベートな受信テーブル変数を取り込みました。絶対的な寛容さは決して良い考えではありません!
シャノン2014年

5
@greektreat:要約すると、データを反復することが唯一のオプションです。その場合でもそれは良い選択肢ではないと主張できるかもしれませんが、これはこの種のコードが不要であり、反対票が必要であることを意味しません。
シャノン2014年

1
SQLでループやカーソルを使用している他の人々に非常に、非常に怒っているインターネットの人々の狂った軍隊がいると思います。このWebサイトで、約30秒後にSQLでループを使用することに言及すれば、受信トレイは無知な人々で溢れ、どんな状況でも使用しないように言われます...
Geoff Griswald

4

コードをもう少し読みやすくしたい場合は、exit変数を使用することもできます。

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

これはおそらく、より複雑なループがあり、ロジックを追跡しようとしている場合に、より適切です。述べたようにループは高価なので、可能であれば他の方法を試してみてください。


つまり...私たちの時代には、データベースサーバーのCPUコアが常に10から20アイドル状態にあり、ストレージコントローラーの利用可能な帯域幅がギガビット単位で測定される時代に住んでいるため、この従来の方法はわかりません。 「LOOP = BAD」が依然として当てはまるという知恵。
Geoff Griswald、

1

WhileループのみがSQLサーバーによって正式にサポートされています。DO whileループの答えはすでにあります。SQL Serverでさまざまな種類のループを実現する方法について詳しく説明しています。

わかっている場合は、とにかくループの最初の反復を完了する必要がある場合、SQLサーバーのDO..WHILEまたはREPEAT..UNTILバージョンを試すことができます。

DO..WHILEループ

DECLARE @X INT=1;

WAY:  --> Here the  DO statement

  PRINT @X;

  SET @X += 1;

IF @X<=10 GOTO WAY;

REPEAT..UNTILループ

DECLARE @X INT = 1;

WAY:  -- Here the REPEAT statement

  PRINT @X;

  SET @X += 1;

IFNOT(@X > 10) GOTO WAY;

FORループ

DECLARE @cnt INT = 0;

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

PRINT 'Done FOR LOOP';

参照


これは、stackoverflow.com / a / 46362450/8239061からのcopy-paste- reorderのようです。
SecretAgentMan

@SecretAgentMan:どちらの回答も異なる質問に答えています。両方の回答で追加のデータが提供されています。
Somnath Muluk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.