基本概念
SQL语句是把结果集作为一个整体(整个作为一个单元)来操作的,但有时候我们需要针对结果集中的每条记录(或某部分记录)进行特殊操作,这时就需要用到游标。
游标是过程化思维,而SQL本身是集合化思维。
针对表中的每一行数据内容调用某个存储过程,或者为每个用户的手机发一条短信。(这个是针对表中每条记录都要做的事情,类似于集合遍历,并且有可能对每条数据执行的操作都不一样)
多数情况下使用查询的性能要比使用游标高效,但并不是任何情况下使用查询性能都高于使用游标。
游标:1.读取次数本身变多 2.没有应用比较好的查询优化,数据库会多sql语句执行多种优化,并选择最优的一种,而对于游标则没有更多的选择。
游标基本语法:
delcare 游标名 cursor [local | global][游标选项] for 查询语句
--1、定义游标
declare cur_CallRecords cursor fast_forward for select * from CallRecords
--2、打开游标
open cur_CallRecords
--========2.1对游标的操作
--将每条数据读取并输出
--2.1.1 将游标向后移动一条
fetch next from cur_CallRecords
--将游标循环向后移动,知道末尾
while @@fetch_status=0 --向后移动成功,后边还有记录
begin
fetch next from cur_CallRecords
end
--3、关闭游标
close cur_CallRecords
--4、释放资源,删除游标中数据库中保存的数据结构
deallocate cur_CallRecords
Local
局部游标(当前存储过程中或批处理等,类似于c#的局部变量)
Global
全局游标(相对于当前连接)
游标选项:
FAST_FORWARD:指定启用了性能优化的 FORWARD_ONLY、READ_ONLY 游标。只能使用fetch next
FORWARD_ONLY :只能向前检索数据。默认选项。
READ_ONLY:只能读取数据,不能修改。禁止通过该游标进行更新。在 UPDATE 或 DELETE 语句的 WHERE CURRENT OF 子句中不能引用游标。
SCROLL:指定所有的提取选项(FIRST、LAST、PRIOR、NEXT、RELATIVE、ABSOLUTE)均可用。
STATIC:定义一个游标,以创建将由该游标使用的数据的临时复本。对游标的所有请求都从 tempdb 中的这一临时表中得到应答;因此,在对该游标进行提取操作时返回的数据中不反映对基表所做的修改,并且该游标不允许修改。
KEYSET:指定当游标打开时,游标中行的成员身份和顺序已经固定。对行进行唯一标识的键集内置在 tempdb 内一个称为 keyset 的表中。
DYNAMIC:定义一个游标,以反映在滚动游标时对结果集内的各行所做的所有数据更改。行的数据值、顺序和成员身份在每次提取时都会更改。动态游标不支持 ABSOLUTE 提取选项。
SCROLL_LOCKS:指定通过游标进行的定位更新或删除保证会成功。将行读取到游标中以确保它们对随后的修改可用时,Microsoft SQL Server 将锁定这些行。如果还指定了 FAST_FORWARD,则不能指定 SCROLL_LOCKS。
OPTIMISTIC:指定如果行自从被读入游标以来已得到更新,则通过游标进行的定位更新或定位删除不会成功。当将行读入游标时 SQL Server 不会锁定行。相反,SQL Server 使用 timestamp 列值的比较,或者如果表没有 timestamp 列,则使用校验和值,以确定将行读入游标后是否已修改该行。如果已修改该行,则尝试进行的定位更新或删除将失败。如果还指定了 FAST_FORWARD,则不能指定 OPTIMISTIC。
TYPE_WARNING:指定如果游标从所请求的类型隐式转换为另一种类型,则向客户端发送警告消息。
Fetch的选项:
NEXT :返回下一条记录。紧跟当前行返回结果行,并且当前行递增为返回行。如果 FETCH NEXT 为对游标的第一次提取操作,则返回结果集中的第一行。NEXT 为默认的游标提取选项。
PRIOR:返回前一条记录。返回紧邻当前行前面的结果行,并且当前行递减为返回行。如果 FETCH PRIOR 为对游标的第一次提取操作,则没有行返回并且游标置于第一行之前。
FIRST:返回第一条记录。
LAST:返回最后一条记录。
ABSOLUTE n :如果n为正数,则返回从第一行开始的行,如果为负数,则返回从最后一行开始的行。
RELATIVE n:相对于当前行移动,如果n为正数则向前移动,如果n为负数则向后移动。
@@CURSOR_ROWS :返回最后一个游标中的数据的行。动态游标返回为-1
declare cur_TblTeacherSalary cursor forward_only
for
select tTId,reward from TblTeacherSalary
declare @teachId int
declare @treward money
open cur_TblTeacherSalary
fetch next from cur_TblTeacherSalary into @teachId,@treward
while @@fetch_status=0
begin
update TblTeacher set tTSalary=tTSalary+@treward where ttid=@teachId
fetch next from cur_TblTeacherSalary into @teachId,@treward
end
close cur_TblTeacherSalary
deallocate cur_TblTeacherSalary
declare @id int
declare @oldSalary money
declare CTblTeacherSalary cursor forward_only for
select ttid from TblTeacherSalary
open CTblTeacherSalary
fetch next from CTblTeacherSalary into @id
while @@fetch_status=0
begin
select @oldSalary=tTsalary from TblTeacher where ttid=@id
update TblTeacherSalary set reward=@oldSalary*0.3+reward where current of CTblTeacherSalary
fetch next from CTblTeacherSalary into @id
end
--where current of用来限定当前游标
close CTblTeacherSalary
deallocate CTblTeacherSalary
把字符串当成sql语句来执行
declare @sql nvarchar(1000)
set @sql='select * from '
set @sql=@sql+'CallRecords'
execute(@sql)
但是表名、列名在ado.net中不能用参数代替,参数一般用在where语句后或者赋值时
使用动态sql很灵活,但是字符串的拼接存在一定的sql注入漏洞攻击,通过各种手段只能减少,不能避免。比如:设置变量的最大长度、将用户输入的内容中替换所有的关键字、特殊符号,设置用户权限:只能查询、禁用数据库中的一些危险功能