2012-09-04 14 views
10

T-SQLでは、カーソルの結果を反復処理するときに、ループWHILEの前にFETCHステートメントを繰り返すのが一般的なようです。 Microsoftからの例以下:カーソルを使用してT-SQLでFETCHが重複しないようにするにはどうすればよいですか?

DECLARE Employee_Cursor CURSOR FOR 
SELECT EmployeeID, Title FROM AdventureWorks2012.HumanResources.Employee 
    WHERE JobTitle = 'Marketing Specialist'; 
OPEN Employee_Cursor; 

FETCH NEXT FROM Employee_Cursor; 
WHILE @@FETCH_STATUS = 0 
    BEGIN 
     FETCH NEXT FROM Employee_Cursor; 
    END; 
CLOSE Employee_Cursor; 
DEALLOCATE Employee_Cursor; 
GO 

FETCH NEXT FROM Employee_Cursor;が2回表示方法に注目してください。)

FETCHは、その後、我々は醜いと、もちろん両方で大きな重複ステートメントを持って、変数の長いリストに選択した場合、 "非DRY"コード。

私が@@FETCH_STATUSがゼロでないときWHILE(TRUE)、その後BREAKに頼る必要があるだろうと思われるので、私は、ポスト条件のフロー制御T-SQLステートメントを認識していませんよ。これは私には気難しい。

その他のオプションはありますか?

+2

は、あなたが示した '' GOTO Employee_Cursor_Fetch'と場所ラベル 'Employee_Cursor_FetchでNEXT Employee_Cursor'からのフェッチ最初に置き換える:'すぐに'FETCH NEXT'を残す。ラベル名はカーソル名( 'Employee_Cursor')から派生していることに気付くことができます。 – miroxlav

答えて

-3

単に、SQLのどこのステートメントがどのように動作するのかということはできません。ループの前に最初の行を取得してから、whileステートメントで再度実行する必要があります。

カーソルを削除し、それを使わずにクエリを解決しようとする方が良い質問です。

+1

強く反対します。重複を避けることはできますが、カーソルを削除することも価値のある目標です。 –

+0

私は、ほとんどの場合、カーソルをセットベースの操作のために避けるべきであることに同意しますが、カーソルが絶対に必要な場合があります。つまり行は行ごとに評価される必要があり、以前に読み込まれた行の結果によって後続の読み取りの結果が決定されます。 – Nick

4

最初のFetchFetch nextでなく、ちょうどfetchであってはなりません。

あなたはあなた自身を繰り返しているわけではありません。 (:)しかし、それは本当に重要ならば、あなたはGOTOを使用することができます - 申し訳ありませんが、M.ダイクストラ)を

私はカーソルを取り払うより多くの労力を費やすだろう、とそれほどDRY教義上、

GOTO Dry 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    --- stuff here 

Dry: 
    FETCH NEXT FROM Employee_Cursor; 
END; 
+0

私は完全にカーソルの立場に同意します。残念ながら、私は一部の行が完全な更新に失敗することなく失敗することを許可する必要があります。私はinsert-into-selectをすべて完了してから、私の選択で失敗したコンバージョンを無視するためにカーソルに頼らざるを得ませんでした。ホーハム。 –

+2

@BernhardHofmann WHERE句を使って先制攻撃を捕まえることはできませんか? – podiluska

6

これは私が(それの恥をOH)に頼ってきたものである:

WHILE (1=1) 
BEGIN 
    FETCH NEXT FROM C1 INTO 
    @foo, 
    @bar, 
    @bufar, 
    @fubar, 
    @bah, 
    @fu, 
    @foobar, 
    @another, 
    @column, 
    @in, 
    @the, 
    @long, 
    @list, 
    @of, 
    @variables, 
    @used, 
    @to, 
    @retrieve, 
    @all, 
    @values, 
    @for, 
    @conversion 

    IF (@@FETCH_STATUS <> 0) 
    BEGIN 
     BREAK 
    END 

    -- Use the variables here 
END 

CLOSE C1 
DEALLOCATE C1 

私が質問を投稿、なぜあなたが見ることができます。私はifステートメントで流れのコントロールが隠されている方法が、whileにあるべきときに好きではありません。

+2

私は、技術的には、これが受け入れられる答えであるべきだと思います。なぜなら、 'FETCH'ステートメントの複製を避けるからです。 – Jeroen

-2

カーソルがレコードセットの現在の行へのポインタであることは明らかです。しかし、それが使用できない限り、単なるポインティングは意味をなさないでしょう。ここではFetchステートメントがシーンに入ります。これは、レコードセットからデータを取り出し、提供された変数に格納します。したがって、最初のfetchステートメントを削除すると、whileループは操作のための "FETCHED"レコードがないので機能しません。最後のfetchステートメントを削除すると、 "while"はループスルーしません。

したがって、完全なレコードセットをループスルーするには、両方ともfetchステートメントが必要です。

+0

それは必要ではありません(上記の私の答えを参照してください)。私はフェッチを2回行う必要があるかどうかではなく、フローの制御を書くことを回避するためのより良い方法を求めていました。 –

8

あり、非常にエレガントにそれをしないChris Oldwood、オンライン投稿の良い構造だ:コードで

DECLARE @done bit = 0 

WHILE (@done = 0) 
BEGIN 
    -- Get the next author. 
    FETCH NEXT FROM authors_cursor 
    INTO @au_id, @au_fname, @au_lname 

    IF (@@FETCH_STATUS <> 0) 
    BEGIN 
    SET @done = 1 
    CONTINUE 
    END 

    -- 
    -- stuff done here with inner cursor elided 
    -- 
END 
関連する問題