2008-10-28 50 views
2

我知道遊標被人們所詬病,我儘量避免使用它們,但可能有一些合理的理由來使用它們。我有一個,我正在嘗試使用一對遊標:一個用於主表,另一個用於輔助表。主表遊標遍歷外循環中的主表。輔助表格光標遍歷內部循環中的輔助表格。 問題是,主表遊標顯然正在進行並將主鍵列值[Fname]保存到本地變量@Fname中,但它沒有獲取輔助表中相應外鍵列的行。對於輔助表,它始終返回其外鍵列值與主表的第一行的主鍵列值相匹配的行。T-Sql光標不能繼續提取

以下是我想要在真實存儲過程中執行的一個非常簡單的示例。 名是主表

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 

請讓我知道我做錯了什麼。 在此先感謝!

回答

2

@fname的價值在評估:DECLARE curScores CURSOR而不是在主循環中。 您必須在主循環中聲明並釋放secon遊標。

+0

謝謝奧維迪烏。那就是訣竅! – Aamir 2008-10-28 19:46:25

0

我想嘗試放置

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

也先裏面,怎麼一回事,因爲你聲明光標僅在第一個name值

1

感謝一些提示,我找到了解決方案。

我不得不DECLARE和DEALLOCATE第一個循環內的輔助遊標。我最初討厭這樣做,因爲我認爲在循環中取消分配資源並不是一個好主意,但我認爲在這種特殊情況下沒有其他辦法可以避免這種情況。 Noew工作代碼看起來有些事情是這樣的:

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 
1

我想你可以與具有行號臨時表,這樣做容易得多:

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

它確實看起來像你問SQL的行爲像一個喜歡循環的語言。它沒有。每當我發現自己在SQL中編寫一個循環時,我問自己,是否必須這樣做? 7/10次的答案是否定的,我可以用集合來代替。