2008-10-28 23 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次的答案是否定的,我可以用集合来代替。