在简单的游标中使用 FETCH
下例为 authors 表中姓以字母 B 开头的行声明了一个简单的游标,并使用 FETCH NEXT 逐个提取这些行。FETCH 语句以单行结果集形式返回由 DECLARE CURSOR 指定的列的值。USE pubs
GO
DECLARE authors_cursor CURSOR FOR
SELECT au_lname FROM authors
WHERE au_lname LIKE "B%"
ORDER BY au_lnameOPEN authors_cursor-- Perform the first fetch.
FETCH NEXT FROM authors_cursor-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN
   -- This is executed as long as the previous fetch succeeds.
   FETCH NEXT FROM authors_cursor
ENDCLOSE authors_cursor
DEALLOCATE authors_cursor
GOau_lname                                 
---------------------------------------- 
Bennet                                   
au_lname                                 
---------------------------------------- 
Blotchet-Halls                           
au_lname                                 
----------------------------------------

解决方案 »

  1.   

    在sqlserver中,使用一个connection来进行多次并发操作的时候,如果这个connection比较繁忙,在firehose(只向前读取并只读的)状态,必须等待connection完成才能做其它任何操作,包括sp_cursorclose.这个时候,系统关闭游标失败,但没有任何提示信息,也不会有错误信息反映到sqlserver中.可能会导致没有任何警告的状态下,游标一直在数据库中处于打开状态。这种状况可能导致2方面结果,一种是游标被留在数据库中占用内存并一直锁定它所操作的纪录,另外一种是在这种状态下,如果试图执行non-firehose的statement,将会发生莫名其妙的(for no apparent reason)发生以下错误:
    SQLState: 24000 [Microsoft][ODBC SQL Server Driver]Invalid cursor state 所以关闭游标之前要确认所有由firehose操作导致的结果是否都已经完成,强烈建议大家尽量不要使用游标操作大数据量的并发操作.
      

  2.   

    如果需要row-by-row地执行,尽量采用非游标技术,如:在客户端循环,用临时表,Table变量,用子查询,用Case语句等等.
      

  3.   

    游标[cursor]就是指向依据一定的条件从数据库中抽取的数据的多个指针。
    游标可以按照它所支持的提取选项进行分类: 
    只进 
    必须按照从第一行到最后一行的顺序提取行。FETCH NEXT 是唯一允许的提取操作,也是默认方式。
    可滚动性 
    可以在游标中任何地方随机提取任意行。
    游标的技术在SQL2000下变得功能很强大,他的目的是支持循环。
    有四个并发选项 
    READ_ONLY:不允许通过游标定位更新(Update),且在组成结果集的行中没有锁。
    OPTIMISTIC WITH valueS:乐观并发控制是事务控制理论的一个标准部分。乐观并发控制用于这样的情形,即在打开游标及更新行的间隔中,只有很小的机会让第二个用户更新某一行。当某个游标以此选项打开时,没有锁控制其中的行,这将有助于最大化其处理能力。如果用户试图修改某一行,则此行的当前值会与最后一次提取此行时获取的值进行比较。如果任何值发生改变,则服务器就会知道其他人已更新了此行,并会返回一个错误。如果值是一样的,服务器就执行修改。 
    选择这个并发选项仁褂没Щ虺绦蛟背械T鹑危砟切┍硎酒渌没б丫云浣辛诵薷牡拇砦蟆Sτ贸绦蚴盏秸庵执砦笫辈扇〉牡湫痛胧┚褪撬⑿掠伪辏竦闷湫轮担缓笕糜没Ь龆ㄊ欠穸孕轮到行薷摹?BR>OPTIMISTIC WITH ROW VERSIONING:此乐观并发控制选项基于行版本控制。使用行版本控制,其中的表必须具有某种版本标识符,服务器可用它来确定该行在读入游标后是否有所更改。在 SQL Server 中,这个性能由 timestamp 数据类型提供,它是一个二进制数字,表示数据库中更改的相对顺序。每个数据库都有一个全局当前时间戳值:@@DBTS。每次以任何方式更改带有 timestamp 列的行时,SQL Server 先在时间戳列中存储当前的 @@DBTS 值,然后增加 @@DBTS 的值。如果某个表具有 timestamp 列,则时间戳会被记到行级。服务器就可以比较某行的当前时间戳值和上次提取时所存储的时间戳值,从而确定该行是否已更新。服务器不必比较所有列的值,只需比较 timestamp 列即可。如果应用程序对没有 timestamp 列的表要求基于行版本控制的乐观并发,则游标默认为基于数值的乐观并发控制。
    SCROLL LOCKS
    这个选项实现悲观并发控制。在悲观并发控制中,在把数据库的行读入游标结果集时,应用程序将试图锁定数据库行。在使用服务器游标时,将行读入游标时会在其上放置一个更新锁。如果在事务内打开游标,则该事务更新锁将一直保持到事务被提交或回滚;当提取下一行时,将除去游标锁。如果在事务外打开游标,则提取下一行时,锁就被丢弃。因此,每当用户需要完全的悲观并发控制时,游标都应在事务内打开。更新锁将阻止任何其它任务获取更新锁或排它锁,从而阻止其它任务更新该行。然而,更新锁并不阻止共享锁,所以它不会阻止其它任务读取行,除非第二个任务也在要求带更新锁的读取。
    滚动锁
    根据在游标定义的 SELECT 语句中指定的锁提示,这些游标并发选项可以生成滚动锁。滚动锁在提取时在每行上获取,并保持到下次提取或者游标关闭,以先发生者为准。下次提取时,服务器为新提取中的行获取滚动锁,并释放上次提取中行的滚动锁。滚动锁独立于事务锁,并可以保持到一个提交或回滚操作之后。如果提交时关闭游标的选项为关,则 COMMIT 语句并不关闭任何打开的游标,而且滚动锁被保留到提交之后,以维护对所提取数据的隔离。
    所获取滚动锁的类型取决于游标并发选项和游标 SELECT 语句中的锁提示。
    锁提示 只读 乐观数值 乐观行版本控制 锁定
    无提示 未锁定 未锁定 未锁定 更新
    NOLOCK 未锁定 未锁定 未锁定 未锁定
    HOLDLOCK 共享 共享 共享 更新
    UPDLOCK 错误 更新 更新 更新
    TABLOCKX 错误 未锁定 未锁定 更新
    其它 未锁定 未锁定 未锁定 更新
    *指定 NOLOCK 提示将使指定了该提示的表在游标内是只读的。