2

カーソルが嫌われていることは承知しており、できるだけ使用しないようにしていますが、使用する正当な理由がある場合もあります。私は 1 つ持っており、1 組のカーソルを使用しようとしています。1 つはプライマリ テーブル用で、もう 1 つはセカンダリ テーブル用です。プライマリ テーブル カーソルは、外側のループでプライマリ テーブルを反復処理します。セカンダリ テーブル カーソルは、内側のループでセカンダリ テーブルを反復処理します。問題は、プライマリ テーブル カーソルが処理を進めてプライマリ キー列の値 [Fname] をローカル変数 @Fname に保存しているように見えますが、セカンダリ テーブルの対応する外部キー列の行を取得しないことです。セカンダリ テーブルの場合、外部キー列の値がプライマリ テーブルの最初の行のプライマリ キー列の値と一致する行を常に返します。

以下は、実際のストアド プロシージャで実行したいことの非常に単純化された例です。Names はプライマリ テーブルです。

SET NOCOUNT ON
DECLARE 
    @Fname varchar(50) -- to hold the fname column value from outer cursor loop
    ,@FK_Fname varchar(50) -- to hold the fname column value from inner cursor loop
    ,@score int
;

--prepare primary table to be iterated in the  outer loop
DECLARE @Names AS Table (Fname varchar(50))
INSERT @Names
    SELECT 'Jim' UNION
    SELECT 'Bob' UNION
    SELECT 'Sam' UNION
    SELECT 'Jo' 


--prepare secondary/detail table to be iterated in the inner loop
DECLARE @Scores AS Table (Fname varchar(50), Score int)
INSERT @Scores
    SELECT 'Jo',1 UNION
    SELECT 'Jo',5 UNION
    SELECT 'Jim',4 UNION
    SELECT 'Bob',10 UNION
    SELECT 'Bob',15 

--cursor to iterate on the primary table in the outer loop
DECLARE curNames CURSOR
FOR SELECT Fname FROM @Names


OPEN curNames
FETCH NEXT FROM curNames INTO @Fname

--cursor to iterate on the secondary table in the inner loop
DECLARE curScores CURSOR
FOR 
    SELECT FName,Score 
    FROM @Scores 
    WHERE Fname = @Fname 
 --*** NOTE: Using the primary table's column value @Fname from the outer loop

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT 'Outer loop @Fname = ' + @Fname

    OPEN curScores
    FETCH NEXT FROM curScores INTO @FK_Fname, @Score

    WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT ' FK_Fname=' + @FK_Fname + '. Score=' + STR(@Score)
        FETCH NEXT FROM curScores INTO @FK_Fname, @Score
    END
    CLOSE curScores
    FETCH NEXT FROM curNames INTO @Fname
END

DEALLOCATE curScores

CLOSE curNames
DEALLOCATE curNames

ここに私が結果のために得るものがあります。外側のループでは最新の Fname が表示されることに注意してください。ただし、その Fname を @Fname として使用して、後続の反復でセカンダリ テーブルから関連する行を取得すると、最初のループに一致する行が取得されます。プライマリ テーブルの行 (Bob)。

Outer loop @Fname = Bob
    FK_Fname=Bob. Score=10
    FK_Fname=Bob. Score=15
Outer loop @Fname = Jim
    FK_Fname=Bob. Score=10
    FK_Fname=Bob. Score=15
Outer loop @Fname = Jo
    FK_Fname=Bob. Score=10
    FK_Fname=Bob. Score=15
Outer loop @Fname = Sam
    FK_Fname=Bob. Score=10
    FK_Fname=Bob. Score=15

私が間違っていることを教えてください。前もって感謝します!

4

4 に答える 4

2

@fName の値は、プライマリ ループではなく、:DECLARE curScores CURSOR で評価されます。1 次ループで 2 番目のカーソルを宣言してから割り当てを解除する必要があります。

于 2008-10-28T16:55:28.073 に答える
1

いくつかのヒントのおかげで、解決策を見つけることができました。

最初のループ内でセカンダリ カーソルを DECLARE および DEALLOCATE する必要がありました。ループ内でのリソースの割り当てと割り当て解除は良い考えではないと思っていたので、最初はそれをするのが嫌いでしたが、この特定の状況でこれを回避する方法は他にないと思います。作業コードは次のようになります。

SET NOCOUNT ON
DECLARE 
    @Fname varchar(50) -- to hold the fname column value from outer cursor loop
    ,@FK_Fname varchar(50) -- to hold the fname column value from inner cursor loop
    ,@score int
;

--prepare primary table to be iterated in the  outer loop
DECLARE @Names AS Table (Fname varchar(50))
INSERT @Names
    SELECT 'Jim' UNION
    SELECT 'Bob' UNION
    SELECT 'Sam' UNION
    SELECT 'Jo' 


--prepare secondary/detail table to be iterated in the inner loop
DECLARE @Scores AS Table (Fname varchar(50), Score int)
INSERT @Scores
    SELECT 'Jo',1 UNION
    SELECT 'Jo',5 UNION
    SELECT 'Jim',4 UNION
    SELECT 'Bob',10 UNION
    SELECT 'Bob',15 

--cursor to iterate on the primary table in the outer loop
DECLARE curNames CURSOR
FOR SELECT Fname FROM @Names


OPEN curNames
FETCH NEXT FROM curNames INTO @Fname

--cursor to iterate on the secondary table in the inner loop
DECLARE curScores CURSOR
FOR 
    SELECT FName,Score 
    FROM @Scores 
    WHERE Fname = @Fname 
 --*** NOTE: Using the primary table's column value @Fname from the outer loop

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT 'Outer loop @Fname = ' + @Fname

    OPEN curScores
    FETCH NEXT FROM curScores INTO @FK_Fname, @Score

    WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT ' FK_Fname=' + @FK_Fname + '. Score=' + STR(@Score)
        FETCH NEXT FROM curScores INTO @FK_Fname, @Score
    END
    CLOSE curScores
    FETCH NEXT FROM curNames INTO @Fname
END

DEALLOCATE curScores

CLOSE curNames
DEALLOCATE curNames

そして、私は正しい結果を得ています:

Outer loop @Fname = Bob
    FK_Fname=Bob. Score=        10
    FK_Fname=Bob. Score=        15
Outer loop @Fname = Jim
    FK_Fname=Jim. Score=         4
Outer loop @Fname = Jo
    FK_Fname=Jo. Score=         1
    FK_Fname=Jo. Score=         5
Outer loop @Fname = Sam
于 2008-10-28T19:45:02.210 に答える
1

行番号を持つ一時テーブルを使用すると、これをはるかに簡単に実行できると思います。

create table #temp1
(
 row int identity(1,1)
 , ... 
)

ループが好きな言語のように振る舞うよう SQL に要求しているように見えます。そうではありません。SQL でループを記述していることに気付くたびに、この方法で実行する必要があるかどうかを自問します。7/10 答えはノーです。代わりにセットでできます。

于 2008-10-28T19:52:13.367 に答える
0

私は配置しようとします

DECLARE curScores CURSOR
FOR 
    SELECT FName,Score 
    FROM @Scores 
    WHERE Fname = @Fname 

最初の while の中で、最初の名前の値に対してのみカーソルを宣言しているため

于 2008-10-28T16:52:01.093 に答える