【问题标题】:T-Sql cursor not proceeding on fetchT-Sql 游标未进行获取
【发布时间】:2008-10-28 16:44:26
【问题描述】:

我知道光标不受欢迎,我尽量避免使用它们,但使用它们可能有一些正当理由。我有一个,我正在尝试使用一对游标:一个用于主表,一个用于辅助表。主表游标在外循环中遍历主表。辅助表游标遍历内部循环中的辅助表。 问题是,虽然主表游标显然继续并将主键列值 [Fname] 保存到局部变量 @Fname 中,但它没有获取辅助表中相应外键列的行。对于辅助表,它总是返回外键列值与主表第一行的主键列值匹配的行。

以下是我想在实际存储过程中执行的一个非常简化的示例。 名称是主表

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

请让我知道我做错了什么。 提前致谢!

【问题讨论】:

    标签: tsql cursors


    【解决方案1】:

    @fName 的值在 :DECLARE curScores CURSOR 中计算,而不是在主循环中。 您必须在主循环中声明并释放第二个游标。

    【讨论】:

      【解决方案2】:

      感谢一些提示,我能够找到解决方案。

      我必须在第一个循环中声明和删除辅助游标。我最初讨厌这样做,因为我认为在循环中分配和释放资源不是一个好主意,但我认为在这种特殊情况下没有其他方法可以避免这种情况。现在工作代码看起来像这样:

      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
      

      【讨论】:

        【解决方案3】:

        我认为使用具有行号的临时表可以更轻松地做到这一点:

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

        看起来您确实要求 SQL 表现得像一种喜欢循环的语言。它没有。每当我发现自己在 SQL 中编写循环时,我都会问自己,是否必须这样做? 7/10 次的答案是否定的,我可以用套装来代替。

        【讨论】:

          【解决方案4】:

          我会尝试放置

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

          在第一个 while 中,因为您只为名字值声明光标

          【讨论】:

            猜你喜欢
            • 2011-04-03
            • 1970-01-01
            • 1970-01-01
            • 2014-11-22
            • 2021-01-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多