SQL之游标
一、游标的概念
游标是一组结果集,就是select查询之后返回的所有行数据的集合。游标其实可以理解成一个定义在特定数据集上的指针,我们可以控制这个指针遍历数据集,或者仅仅是指向特定的行。
游标(Cursor)的优点:
- 是处理数据的一种方法。
- 它可以定位到结果集中的某一行,对数据进行读写。
- 也可以移动游标定位到你需要的行中进行数据操作。
- 是面向集合的数据库管理系统和面向行的程序设计之间的桥梁
- 作为一个备用方式,当我们穷尽了while循环,子查询,临时表,表变量,自建函数或其他方式仍然无法实现某些查询的时候用游标来实现。
游标(Cursor)的缺点:
- 游标会吃更多的内存,减少可用的并发,占用宽带,锁定资源还有更多的代码量。
一个完整的游标由5部分组成:
(1)声明游标 (2)打开游标 (3)从一个游标中查找信息 (4)关闭游标 (5)释放游标
一、声明游标
简单版:
declare cursor_name [global/local] cursor for select * from table1 go
--一个例子(定义后直接赋值):
DECLARE cursor_name CURSOR FOR
SELECT * FROM TABLE1
--用GO结束上面作用域
GO
--下面是oracle的一个例子:
DECLARE CURSOR cursor_name is select * from tablename where id is null;
一些参数解释:
cursor_name:游标名称。
Local:作用域为局部,只在定义它的批处理,存储过程或触发器中有效。
Global:作用域为全局,由连接执行的任何存储过程或批处理中,都可以引用该游标。
全局游标global在批处理结束后依然有效,局部游标local在批处理结束后被隐式释放,无法在其他批处理中调用,默认是global
声明游标还有更复杂的参数(完整的声明形式):
完整版:
DECLARE cursor_name CURSOR [ LOCAL |GLOBAL ] [ FORWARD_ONLY | SCROLL ] [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] [ TYPE_WARNING ] FOR select_statement [ FOR UPDATE [ OF column_name [ ,...n ] ] ]
cursor_name:游标名称。
Local:作用域为局部,只在定义它的批处理,存储过程或触发器中有效。
Global:作用域为全局,由连接执行的任何存储过程或批处理中,都可以引用该游标。
Forward_Only:指定游标智能从第一行滚到最后一行。 Fetch Next是唯一支持的提取选项。如果在指定Forward_Only时不指定Static、KeySet、Dynamic关键字,默认为Dynamic游标。如果Forward_Only和Scroll没有指定,Static、KeySet、Dynamic游标默认为Scroll,Fast_Forward默认为Forward_Only
Static:静态游标
KeySet:键集游标
Dynamic:动态游标,不支持Absolute提取选项
Fast_Forward:指定启用了性能优化的Forward_Only、Read_Only游标。
Read_Only:意味着声明的游标只能读取数据,游标不能做任何更新操作
Scroll_Locks:将读入游标的所有数据进行锁定,防止其他程序进行更改,以确保更新的绝对成功
Optimistic:是相对比较好的一个选择,OPTIMISTIC不锁定任何数据,当需要在游标中更新数据时,如果底层表数据更新,则游标内数据更新不成功,如果,底层表数据未更新,则游标内表数据可以更新。
Type_Warning:指定将游标从所请求的类型隐式转换为另一种类型时向客户端发送警告信息。
For Update[of column_name ,....] :定义游标中可更新的列。
二、打开游标
open cursor_name 注意当全局游标和局部游标变量重名时,默认会打开局部变量游标
全局游标在批处理结束后依然有效
局部游标在批处理结束后被隐式释放,无法再其他批处理中引用
oracle的一个例子:
OPEN CURSOR cursorname
三、从一个游标中查找信息
Fetch
[ [Next|prior|Frist|Last|Absoute n|Relative n ]
from
[Global] cursor_name
into @variable_name[,....]]
一个例子(取当前位置的下一行,将提取到的数据存放到变量id,name中):
fetch next from cursor_name into @id,@name
一些参数解释:
Frist:结果集的第一行
Prior:当前位置的上一行
Next:当前位置的下一行
Last:最后一行
Absoute n:从游标的第一行开始数,第n行。
Relative n:从相对当前位置数,第n行。(n为负数向前数,否则向后)
Into @variable_name[,...] : 将提取到的数据存放到变量variable_name中。
注意: 对于未指定SCROLL选项的游标来说,只支持NEXT取值.
oracle的一个例子:
DECLARE TYPE cursorname IS REF CURSOR
RETURN tablename%ROWTYPE;
DECLARE custrecord tablename%ROWTYPE
BEGIN
OPEN cursorname;
FETCH cursorname into custrecord;
CLOSE cursorname;
END;
在这个例子中,FETCH用来检索当前行(自动从第一行开始),放到声明变量custrecord中,对检索出来的数据不做任何处理。
oracle的另一个例子(含循环语句):
DECLARE TYPE cursorname IS REF CURSOR
RETURN tablename%ROWTYPE;
DECLARE custrecord tablename%ROWTYPE
BEGIN
OPEN cursorname;
LOOP
FETCH cursorname into custrecord;
EXIT WHEN cursorname%NOTFOUND;
……
END LOOP;
CLOSE cursorname;
END;
在这个例子中,FETCH用来检索当前行(自动从第一行开始),放到声明变量custrecord中,这里的FETCH放到LOOP中,EXIT WHEN cursorname%NOTFOUND这句话使在取不出更多的行时退出循环,该例子对检索出来的数据不做任何处理。
四、关闭游标
close+游标名称
CLOSE cursorname
五、释放游标
deallocate+游标名称
oracle用法:
DEALLOCATE CURSOR cursorname
一旦游标关闭,如果不再次打开,将不能使用,第二次使用他时不需要再声明,只需要open打开它即可。
下面是一个完整的例子:
表数据:
处理过程:
--声明游标 declare test_Cursortable3 CURSOR FOR SELECT id,NAME FROM TABLE3 --打开游标 OPEN test_Cursortable3 --声明游标提取变量所要存放的变量 declare @id int,@name varchar(20) --定位游标到哪一行 fetch next from test_Cursortable3 into @id,@name --into的变量数量必须需与游标查询结果的列数相同 --fetch FIRST from test_Cursortable3 into @id,@name while @@FETCH_STATUS=0 --提取成功,进行下一条数据的提取操作 begin if @id=2 begin Update TABLE3 Set sex='0' Where Current of test_Cursortable3 --更新当前行 end if @id=10 begin delete TABLE3 where current of test_Cursortable3 --删除当前行 end fetch next from test_Cursortable3 into @id,@name --移动游标 end --关闭游标 close test_Cursortable3 --释放游标 deallocate test_Cursortable3
处理结果:
最后,使用游标时注意事项:
- 如果能不用游标,尽量不要使用游标。
- 用过之后一定要关闭和释放。
- 尽量不要在大量数据上定义游标(一万行以上)。
- 尽量不要使用游标上更新数据。
- 尽量不要使用insensitive, static和keyset这些参数定义游标。
- 如果可以,尽量使用FAST_FORWARD关键字定义游标。
- 如果只对数据进行读取,当读取时只用到FETCH NEXT选项,则最好使用FORWARD_ONLY参数
原文链接:https://www.cnblogs.com/jdzhang/p/7576520.html