【问题标题】:What is the use of a cursor in SQL Server?SQL Server 中游标的用途是什么?
【发布时间】:2011-05-12 11:50:35
【问题描述】:

我想使用数据库游标;首先我需要了解它的用途和语法是什么,在什么场景下我们可以在存储过程中使用它?不同版本的 SQL Server 有不同的语法吗?

什么时候需要使用?

【问题讨论】:

标签: sql-server database-cursor


【解决方案1】:

游标是一种显式枚举结果集行的机制,而不是像这样检索它。

但是,虽然对于习惯于编写 While Not RS.EOF Do ... 的程序员来说,使用它们可能更舒服,但如果可能的话,在 SQL Server 存储过程中通常要避免使用它们——如果你可以编写一个查询而不使用游标,你给优化器一个更好的机会来找到一个快速的方法来实现它。

老实说,除了一些管理任务(例如遍历目录中的所有索引并重建它们)之外,我从来没有找到一个无法避免的游标的实际用例。我想它们可能在报告生成或邮件合并中有一些用途,但在与数据库对话的应用程序中进行类似游标的工作可能更有效,让数据库引擎做它最擅长的事情——设置操作。

【讨论】:

  • +1 大多数时候它们是不必要的。仅在一次性工作或所有其他选项都失败时使用它们。
  • 我发现对游标的唯一真正需要是与触发器相关时 - 如果您有多个记录受到影响,并且您想为每条记录执行一个存储过程,您需要通过触发器表(例如“INSERTED”)
  • 那么游标是用来遍历一个结果集的行,比如将100行的状态从挂起更新为完成?
  • @SelectDistinct 它用于直接在 DBMS 可编程性模型中迭代结果集的行,例如在触发器或存储过程中;正如 RPM1984 所说,一个典型的用例是为给定结果集的每一行运行一个存储过程,特别是如果您的可编程性模型不允许将结果集值作为参数。
  • @nice 解释即使我找不到一个必须使用光标的实时示例
【解决方案2】:

游标可用于逐行检索数据。它的作用类似于循环语句(即while 或for 循环)。 要在 SQL 过程中使用游标,您需要执行以下操作: 1.声明一个定义结果集的游标。 2.打开游标建立结果集。 3.根据需要从游标中取数据到局部变量中,一次一行。 4.完成后关闭光标。

例如:

declare @tab table
(
Game varchar(15),
Rollno varchar(15)
)
insert into @tab values('Cricket','R11')
insert into @tab values('VollyBall','R12')

declare @game  varchar(20)
declare @Rollno varchar(20)

declare cur2 cursor for select game,rollno from @tab 

open cur2

fetch next from cur2 into @game,@rollno

WHILE   @@FETCH_STATUS = 0   
begin

print @game

print @rollno

FETCH NEXT FROM cur2 into @game,@rollno

end

close cur2

deallocate cur2

【讨论】:

    【解决方案3】:

    使用光标是因为在子查询中我们可以逐行获取记录 所以我们使用游标来获取记录

    光标示例:

    DECLARE @eName varchar(50), @job varchar(50)
    
    DECLARE MynewCursor CURSOR -- Declare cursor name
    
    FOR
    Select eName, job FROM emp where deptno =10
    
    OPEN MynewCursor -- open the cursor
    
    FETCH NEXT FROM MynewCursor
    INTO @eName, @job
    
    PRINT @eName + ' ' + @job -- print the name
    
    WHILE @@FETCH_STATUS = 0
    
    BEGIN
    
    FETCH NEXT FROM MynewCursor 
    INTO @ename, @job
    
    PRINT @eName +' ' + @job -- print the name
    
    END
    
    CLOSE MynewCursor
    
    DEALLOCATE MynewCursor
    

    输出:

    ROHIT                           PRG  
    jayesh                          PRG
    Rocky                           prg
    Rocky                           prg
    

    【讨论】:

    • 我们可以从简单的查询'Select eName,job FROM emp where deptno =10'中得到相同的结果,那么为什么要使用游标来循环它,有什么实际用途吗?
    • 我有一个问题,我可以像在 google 中找到的所有示例都使用 PRINT 'Name : '+@name+ ', pagename : '+convert(varchar(20),@salary) 一样,在光标中设置用户结果集,但我可以将结果集从这里返回到 c# 吗?
    【解决方案4】:

    我认为,当您想要比较返回集的不同行上的特征时,或者如果您想在某些情况下编写与标准格式不同的输出行格式时,您可能想要使用游标。想到两个例子:

    1. 有一所大学,其中每个班级的添加和删除在表中都有自己的行。这可能是一个糟糕的设计,但您需要跨行进行比较以了解您有多少添加和删除行,以确定该人是否在课堂上。我想不出只用 sql 就能做到这一点的直接方法。

    2. 另一个示例是为 GL 日记帐编写日记帐总行。您的日记帐中有任意数量的借方和贷方,您的行集回报中有许多日记帐,并且您希望在每次完成日记帐时写入日记帐总行以将其过帐到总帐中。使用光标,您可以知道您何时离开一个日记帐并开始另一个日记帐,并为您的借方和贷方设置了累加器,并编写了一个不同于借方/贷方行的日记帐总行(或表格插入)。

    【讨论】:

      【解决方案5】:

      Cursor 本身是一个迭代器(如 WHILE)。通过说迭代器,我的意思是一种遍历记录集(也就是一组选定的数据行)并在遍历时对其进行操作的方法。例如,操作可以是 INSERT 或 DELETE。因此,例如,您可以将其用于数据检索。游标按顺序处理结果集的行 - 逐行。游标可以看作是指向一组行中的一行的指针,一次只能引用一行,但可以根据需要移动到结果集中的其他行。

      link 可以清楚地解释其语法并包含附加信息和示例。

      游标也可以在 Sprocs 中使用。它们是一种快捷方式,允许您使用一个查询而不是多个查询来完成一项任务。但是,游标识别范围并被视为未定义超出存储过程的范围,并且它们的操作在单个过程中执行。存储过程无法打开、获取或关闭未在过程中声明的游标。

      【讨论】:

        【解决方案6】:

        在 SQL Server 中,当您需要时使用游标而不是 T-SQL 命令一次对结果集中的所有行进行操作,而是在需要更新数据库表中的记录时使用游标以单例方式,即逐行获取。一次获取一行或逐行获取。

        使用游标包括几个步骤:

        Declare - Declare 用于定义一个新的游标。 打开 - 通过执行游标定义的 SQL 语句打开和填充游标。 Fetch - 打开游标时,可以从游标中逐一检索行。 关闭 - 在数据操作之后,我们应该明确地关闭游标。 Deallocate - 最后,我们需要删除游标定义并释放所有与游标相关的系统资源。 语法

        DECLARE cursor_name CURSOR [ LOCAL |全球 ] [ FORWARD_ONLY |滚动 ] [ 静态 |键盘 |动态 | FAST_FORWARD ] [ 只读 |滚动锁定 |优化 ] [ TYPE_WARNING] FOR select_statement [FOR UPDATE [ OF column_name [ ,...n ] ] ] [;]

        【讨论】:

          【解决方案7】:
          CREATE PROCEDURE [dbo].[SP_Data_newUsingCursor]
          (
              @SCode NVARCHAR(MAX)=NULL,
              @Month INT=NULL,
              @Year INT=NULL,
              @Msg NVARCHAR(MAX)=null OUTPUT
          )
          AS
          
          BEGIN
           
              DECLARE @SEPERATOR as VARCHAR(1)
              DECLARE @SP INT
              DECLARE @VALUE VARCHAR(MAX)
              SET @SEPERATOR = ','
              
              CREATE TABLE #TempSiteCode (id int NOT NULL)
              
              WHILE PATINDEX('%' + @SEPERATOR + '%', @SCode ) <> 0 
                  BEGIN
                          SELECT  @SP = PATINDEX('%' + @SEPERATOR + '%' ,@SCode)
                          SELECT  @VALUE = LEFT(@SCode , @SP - 1)
                          SELECT  @SCode = STUFF(@SCode, 1, @SP, '')  
                          INSERT INTO #TempSiteCode (id) VALUES (@VALUE)
                  END
          
          
          DECLARE 
          @EmpCode bigint=null,
          @EmpName nvarchar(50)=null
          
          CREATE TABLE #TempEmpDetail
          (
              EmpCode bigint
          )
          
          
          CREATE TABLE #TempFinalDetail
          (   
              EmpCode bigint,
              EmpName nvarchar(500)
              
              
          )
          
          
          DECLARE @TempSCursor CURSOR
          DECLARE @TempFinalCursor CURSOR
          
          
          
          INSERT INTO #TempEmpDetail
          (
              EmpCode
          )
          (
          
          SELECT DISTINCT EmpCode FRom tbl_Att_MSCode
          WHERE tbl_Att_MSCode.SiteCode IN (SELECT id FROM #TempSiteCode)
          AND fldMonth=@Month AND fldYear=@Year
          
          )
          
          SET @TempSiteFinalCursor=CURSOR FOR SELECT EmpCode FROM #TempEmpDetail
          OPEN @TempSiteFinalCursor
          FETCH NEXT FROM @TempSiteFinalCursor INTO @EmpCode,@SiteCode,@HrdCompanyId
          
          WHILE @@FETCH_STATUS=0
              BEGIN
                  
                  SEt @EmpName=(SELECt EmpName FROm tbl_Employees WHERE EmpCode=@EmpCode)
          
                  INSERT INTO #TempFinalDetail
                  (       
                      EmpCode,
                      EmpName
                  )
          
                  VALUES
                  (
                   
                    @EmpCode,
                    @EmpName
                   )
          
          
                   FETCH NEXT FROM @TempSiteFinalCursor INTO @EmpCode
              END
          
          
              SELECT  EmpCode,
                      EmpName
                      FROM #TempFinalDetail
          
          
          DEALLOCATE @TempSiteFinalCursor
          
          DROP TABLE #TempEmpDetail
          DROP TABLE #TempFinalDetail
          
          END
          

          【讨论】:

            猜你喜欢
            • 2012-09-08
            • 1970-01-01
            • 2011-10-14
            • 2013-10-22
            • 2013-07-20
            • 1970-01-01
            • 2016-09-02
            • 1970-01-01
            • 2012-06-07
            相关资源
            最近更新 更多