2-4 游标技术

简介:
2-4 游标技术
u       了解游标的基本概念及特点,学会使用游标的基本步骤
u       掌握两个系统全局变量:@@cursor_rows@@FETCH_ STATUS在定义游标中的作用,掌握在游标中使用FETCH获取游标技术,掌握FETCH语句使用过程中的移动关键词。
u       掌握如何使用游标修改或删除数据
u       了解如何使用递归游标遍历树算法解决家族树的问题
u       了解改进的非游标查询策略
 
游标实际上是用户在系统中开设的一个数据缓冲区,存放 SQL 语句的执行结果。到目前为止,所有的 SQL 语句是采用面向集合的方法来处理和操作数据的,是针对行的集合进行的操作。应用 WHERE 子句指出的行包含在该集合之中,必须对每一行进行同样的工作。例如:返回集合的条件行( SELECT ),改变集合中的每一行的同一个列( UPDATE ),删除集合中的每一个行( DELETE )等。
游标具体使用的过程是:游标中存放查询结果的一组记录,用户可以通过移动游标指针逐一访问记录,获得结果,并赋给主变量,交由主语言进一步处理。
游标技术的引入最根本解决的问题是替代了面向集合的数据信息操作方法,试图通过数据结构指针的方法进行数据的定位查询,这就是游标概念引入的目的。它允许每次一行的操作,基于行的内容,可以决定采取的下一步行为。
  注意:我们在使用游标之前务必清楚的了解下面的两点:
q         游标是有害的!!在实际测试中,游标的效率是正常SQL select 查询的1/501/70
q         不得不按照每次一行的方式来处理行(游标)时候的性能,开销相对于面向集合的方式来处理行的性能是巨大的。在解决使用游标之前,应该确定已经仔细分析了需求,并且无法通过别的编程方法来解决问题。某些情况下面,游标是非常有用的,但是它应当是程序设计员最后的手段,而并不应当成为第一的选择!
2-4-1 使用游标的基本步骤
使用游标共分五个步骤,分别是:声明游标,打开游标,利用游标读取、修改或删除所取的行,关闭游标,释放游标。
1. 声明游标:
为游标指定获取数据时候的 select 语句。声明的游标并不会检索任何的数据,仅仅为游标指定 select 的查询范围。
Declare  游标名称  cusor cursoroptions
For select 语句
2. 打开游标
Open    游标名称
3. 取出游标中的信息
Fetch    游标名称    into @ 变量 1  @ 变量 2
该操作将使得游标移动到下一行记录,并将游标返回的每个列的数据分别赋值给本地变量,这些变量必须预先予以声明。
4. 关闭游标
关闭游标的目的是释放数据和系统资源,但是保留 select 语句,以后还可以通过 open 方法打开( open 命令与 close 相似)。
Close      游标名称
释放游标,释放相关内存,并删除游标定义
Deallocate       游标名称
实验:建立游标的基本实验
--1:请按照下面的步骤建立游标
use school
GO
--
  
FOR
SELECT sname FROM student
--
OPEN stu_cursor
--
FETCH NEXT FROM stu_cursor
--
close stu_cursor
--
deallocate stu_cursor
2-4-2 在游标中使用 FETCH
在游标的使用中我们经常会用到两个系统全局变量: @@cursor_rows @@FETCH_ STATUS ,下面我们就这两个系统全局变量进行说明。
1. @@cursor_rows
     返回连接上最后打开的游标中当前存在的合格行的数量。
2. @@FETCH_ STATUS
会被  FETCH  语句执行的最后游标的状态,而 @@fetch_status 标量的意义是: 0—— 最近一次 fetch 命令成功的获取到一行数据; 1—— 最近一次 fetch 命令到达结果集的尾部; 2—— 最近一次获取的行不可用,该行已经被删除。
实验 1 :在简单的游标中使用  FETCH
USE school
GO
DECLARE @sname varchar(40)
DECLARE stu_cursor CURSOR
FOR
 SELECT sname FROM student 
OPEN stu_cursor
FETCH NEXT FROM stu_cursor
INTO @sname
WHILE @@FETCH_STATUS = 0
BEGIN
       PRINT '
       FETCH NEXT FROM stu_cursor    INTO @sname
END
CLOSE stu_cursor
DEALLOCATE stu_cursor
GO
刚才我们看到关键词:  FETCH NEXT 是推动游标向前移动的关键,除此以外, FETCH 还包括以下的移动关键词,如表 2-6 所示。
2-6 FETCH 移动关键词
关键字
移动位置
FIRST
数据集第一条记录
LAST
数据集末一条记录
PRIOR
前一条记录
NEXT
后一条记录
RELATIVE
按照相对位置决定移动的位置
ABSOLUTE
按照绝对位置决定移动的位置
实验 2 :在简单的游标中使用  FETCH
--1
DECLARE @sname varchar(40) --定义游标阶段
DECLARE stu_cursor CURSOR
FOR
 SELECT sname FROM student
            
--定义并打开游标阶段
declare @sname varchar(20)
FETCH NEXT FROM stu_cursor
INTO @sname
print @sname                  --读取并显示游标阶段
 
declare @sname varchar(20)
FETCH prior FROM stu_cursor
INTO @sname
print @sname
-- 小问题:系统将报错提示:“fetch: 提取类型 prior 不能用于只进游标。这是为什么?”
--2:语法改进
DECLARE @sname varchar(40)
DECLARE stu_cursor CURSOR scroll –- 注意差异之处
FOR
 ……                     --其余地方同例1一致,此处略。
--3:通过游标技术循环打印学生姓名,每个姓名之间用逗号分隔
DECLARE @sname varchar(30),@s varchar(400)
DECLARE stu_cursor CURSOR
FOR
SELECT sname FROM student
OPEN stu_cursor
FETCH NEXT FROM stu_cursor INTO @s
WHILE @@FETCH_STATUS = 0
BEGIN
   FETCH NEXT FROM stu_cursor
   INTO @sname
   set @s=ltrim(rtrim(@s))+','+ltrim(rtrim(@sname))
END
--开始打印姓名
print @s
CLOSE stu_cursor
DEALLOCATE stu_cursor   --关闭并释放游标资源
GO
-- 小问题:为什么最后一行总是重复出现呢?如何解决这个问题?
实验 3 :使用游标修改或删除数据
DECLARE abc CURSOR
FOR
    SELECT sName FROM Student
OPEN abc
GO
 
FETCH NEXT FROM abc
GO
UPDATE student SET sName = '
GO
CLOSE abc
DEALLOCATE abc
GO
实验 4 :复杂的游标查询问题 —— 使用递归游标遍历树算法解决家族树的问题
--
--
  
create procedure family_all(@me_id int)
--
as
declare @child_id int,@child_name varchar(30)
declare cchild cursor local fast_forward
--
 for
 select person_id,person_name from person  where person.father_id=@me_id or person.mother_id=@me_id
 order by date_birth
--
open cchild
fetch cchild into @child_id,@child_name
--
while @@fetch_status=0
begin
print space(@@nestlevel*2)+'+'+cast(@child_id as varchar(6))+''+@child_name
--
--@@NESTLEVEL 
     exec family_all @child_id
--
     fetch cchild into @child_id,@child_name
--
end
close cchild
deallocate cchild
exec family_all 2
  注意:
当游标较少时候,使用该算法解决遍历问题已经足够;但是当数据量较大时候,就会出现问题。主要由两个原因造成:
q         MSSQL限制存储过程循环次数最多32层。
q         性能问题。基于行的游标比基于集合的查询性能上面将慢5070倍。如果假设将500万行数据组织为12个层次,需要进行游标调用500万次,开辟500万个缓冲空间,执行500万次的select查询。
实验 5 :复杂的游标查询问题 —— 改进的非游标查询策略
--
create table familytree
(person_id int, generation int, familyline varchar(20) default '')
 
declare @generation int,@firsperson int
set @generation=1
set @firsperson=1
--
insert familytree(person_id,generation,familyline)
select @firsperson,@generation,@firsperson
 
while @@rowcount>0
 begin
 set @generation=@generation+1
 insert familytree(person_id,generation,familyline)
    select person.person_id,@generation,familytree.familyline+''+str(person.person_id,5)
    from person
    inner join familytree
    on familytree.generation=@generation-1
       and (familytree.person_id=person.mother_id
            or familytree.person_id=person.father_id)
 end
--
select * from familytree
drop table familytree




本文转自 qianshao 51CTO博客,原文链接:http://blog.51cto.com/qianshao/348298,如需转载请自行联系原作者

目录
相关文章
|
3月前
|
存储 SQL 关系型数据库
触发器和游标区别
触发器(Trigger)和游标(Cursor)是关系型数据库中常见的两个概念,它们在功能和使用上有一些区别。下面是触发器和游标的主要区别:
187 1
|
3月前
|
存储 关系型数据库 MySQL
十九、游标 Cursor
十九、游标 Cursor
25 0
|
存储 SQL 数据可视化
MySQL_01--游标CURSOR--通过游标(CURSOR)实现对select选择集的迭代使用,解决在Navicat中声明游标就一直报错的问题
我的需求是,一条一条的读取并使用select选择集的结果,使用的数据库可视化软件是Navicat。 但是我在使用游标的过程中一直在游标声明处就报错,试了很多方法,改名字,调整变量顺序都不管用,最后发现,游标需要定义在存储过程(Stored Procedure)函数里。
|
SQL 数据处理 数据库管理
|
API 数据库 数据库连接