【问题标题】:How to use cursor within cursor in SQL Server?如何在 SQL Server 的游标中使用游标?
【发布时间】:2017-01-18 07:32:24
【问题描述】:

我有以下查询,我想在查询中使用嵌套游标。怎么做,因为它没有运行,而且我是 SQL Server 的新手。请帮帮我

CHECK TABLE SUGGEST LAT 31.8181 LONG 71.4146

消息 16915,级别 16,状态 1,过程 Sp_CheckCarStatusMeter,行 266
名称为“ShapeCursor”的光标已存在。其他打开 光标

消息 16905,级别 16,状态 1,过程 Sp_CheckCarStatusMeter, 296号线
光标已打开。

代码:

DECLARE SuggestCursor CURSOR FOR  
    SELECT TOP 100 
        rtha.car_id, rtha.latitude, rtha.longitude 
    FROM   
        Carhistory rtha 
    WHERE 
        rtha.car_id = 6142 ;

OPEN SuggestCursor;  

FETCH NEXT FROM SuggestCursor INTO @CarSuggested, @carlatprevious, @carlongprevious;  

WHILE (@@FETCH_STATUS = 0)  
BEGIN  
    PRINT 'CHECK TABLE SUGGEST LAT '+@carlatprevious +' LONG '+ @carlongprevious;

    DECLARE ShapeCursor CURSOR FOR  
         SELECT 
             g.ID, @carID, g.ShapeType  
         FROM   
             tblgeo AS g  
         WHERE  
             car_id @ID;   

    IF (SELECT CURSOR_STATUS('local','ShapeCursor')) >= -1
    BEGIN
        Print 'DEALLOCATE CURSOR'
       --DEALLOCATE ShapeCursor
    END   
    ELSE    
        Print 'ELSE OPEN CURSOR'

    OPEN ShapeCursor;

    FETCH NEXT FROM ShapeCursor INTO @ID, @CarIdx, @ShapeType;  

    WHILE (@@FETCH_STATUS = 0) 
    BEGIN 

【问题讨论】:

  • 我们需要查看更多代码才能确定,因为您只显示了顶部。由于您要在循环中声明游标,因此一个明显的问题是您是否还没有在循环的每个循环中释放它。话虽这么说,尤其是因为您说您是 SQL 新手,通常最好避免使用游标,除非已经探索了所有其他途径,并且 嵌套 游标很少(如果有的话)是问题的正确解决方案.如果您能描述您的目标,以及一些示例数据和预期结果,我们或许能够提供一个完全不使用游标的解决方案。
  • 光标是邪恶的。嵌套游标更糟糕。除非你真的别无选择,否则不要使用它们。话虽如此,如果您确实必须使用嵌套游标,则必须在外部游标的循环之外声明(并释放)内部游标。
  • 重写查询,使其不使用游标。光标非常邪恶。它们是您可以在任何数据库中使用的最危险的东西。
  • 你想用这段代码做什么?从这段代码中无法理解。不管是什么,都有更简单、更快捷的方法来做到这一点。例如,有很多连接字符串的解决方案,SQL Server 2016 甚至有一个STRING_AGG 函数

标签: sql-server sql-server-2012 sql-server-2008-r2


【解决方案1】:

嵌套游标示例:

DECLARE
        @crTables CURSOR,
        @crColumns CURSOR,
        @table_id INT,
        @table_name VARCHAR(100),
        @column_id INT,
        @column_name VARCHAR(100)

SET @crTables = CURSOR FAST_FORWARD FOR 
SELECT TOP 10 [object_id], NAME
FROM sys.tables t
ORDER BY t.[object_id] DESC

OPEN @crTables

FETCH NEXT FROM @crTables
INTO @table_id, @table_name

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @table_name + ': '

    SET @crColumns = CURSOR FAST_FORWARD FOR 
    SELECT TOP 10 c.column_id, c.name
    FROM sys.[columns] c
    WHERE c.[object_id] = @table_id
    ORDER BY c.column_id

    OPEN @crColumns

    FETCH NEXT FROM @crColumns
    INTO @column_id, @column_name

    WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT @column_name

        FETCH NEXT FROM @crColumns
        INTO @column_id, @column_name
    END

    CLOSE @crColumns
    DEALLOCATE @crColumns

    PRINT ''

    FETCH NEXT FROM @crTables
    INTO @table_id, @table_name
END

CLOSE @crTables
DEALLOCATE @crTables

GO

这将给出相同的结果:

GO

DECLARE @txt VARCHAR(MAX)

SET @txt = 
STUFF(
    (
    SELECT TOP 10
        CHAR(13) + CHAR(10) + NAME
        + (
                SELECT TOP 10 CHAR(13) + CHAR(10) + c.name
                FROM sys.[columns] c
                WHERE c.[object_id] = t.[object_id]
                ORDER BY c.column_id
                FOR XML PATH(''), TYPE
            ).value('.', 'VARCHAR(MAX)')
        + CHAR(13) + CHAR(10)
    FROM sys.tables t
    ORDER BY t.[object_id] DESC
    FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)'), 1, 2, '')

PRINT @txt

尽量避免使用游标。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多