MS SQL Server-游标内部的游标需要很长时间

时间:2018-07-18 12:00:45

标签: sql-server

我有以下代码:

CREATE OR ALTER PROCEDURE TEST
AS
    DECLARE @text_var nvarchar(200),
            @num_var numeric(27, 4);

    DECLARE c_cur1 CURSOR FOR
        SELECT DISTINCT TOP 2
               textID
        FROM text_table
        WHERE status = 'Approved';

    OPEN c_cur1;

    FETCH NEXT FROM c_cur1
    INTO @text_var;

    WHILE @@fetch_status = 0
    BEGIN

        PRINT 'first cursor: ' + @text_var;

        DECLARE c_cur2 CURSOR FOR
            SELECT TOP 1
                   numID
            FROM num_table
            WHERE text = @text_var
            ORDER BY cdate DESC;

        PRINT 'before opening second cursor';

        OPEN c_cur2;

        FETCH NEXT FROM c_cur2
        INTO @num_var;

        WHILE @@fetch_status = 0
        BEGIN

            PRINT 'Inside second cursor' + @text_var;

        END;

        CLOSE c_cur2;

        DEALLOCATE c_cur2;

        FETCH NEXT FROM c_cur1
        INTO @text_var;

    END;

    CLOSE c_cur1;

    DEALLOCATE c_cur1;

“第二个光标内”文本被打印了好几次(至少应该超过1000次),而我认为应该只有两次。

因此,此查询至少需要30分钟才能运行。

请提示以上代码中是否有错误

1 个答案:

答案 0 :(得分:0)

之所以经常循环,是因为您将c_cur2中的下一个提取操作放错了位置。它应位于与相关WHILE关联的BEGIN..END块中,如下所示。实际上,您正在导致无限循环。

CREATE PROCEDURE TEST AS

DECLARE @text_var nvarchar(200), @num_var numeric(27,4)

DECLARE c_cur1 CURSOR for select distinct top 2 textID from text_table where status = 'Approved';

open c_cur1

fetch next from c_cur1 into @text_var

    While @@fetch_status = 0 
    BEGIN

        PRINT 'first cursor: ' + @text_var

        declare c_cur2 CURSOR for select top 1 numID from num_table where text = @text_var order by cdate desc;

        PRINT 'before opening second cursor'

        open c_cur2
        fetch next from c_cur2 into @num_var    
        while @@fetch_status = 0

        BEGIN

            PRINT 'Inside second cursor' + @text_var
            fetch next from c_cur2 into @num_var
        END

        CLOSE c_cur2

        DEALLOCATE c_cur2

        FETCH NEXT FROM c_cur1 INTO @text_var

    END

CLOSE c_cur1

DEALLOCATE c_cur1

尽管出于学习目的可以使用游标,但应该将其替换为基于集合的解决方案。