马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、游标
1、游标
- 一个对表举行操作的SQL语句(如 select)通常都可产生或处理一组记录,但是许多应用不能把整个结果集作为一个单位来处理,以是就须要一种机制来保证每次处理结果此中的一行或几行,游标(cursor)就提供了这种机制。
- SQL Server 通过游标提供了对一个结果集举行逐行处理的能力,游标可看做一种特别的指针,它与某个查询结果相联系,可以指向结果集的任意位置,以便对指定位置的数据举行处理。使用游标可以在查询数据的同时对数据举行处理。
- 游标是系统为用户开设的一个数据缓冲区,存放SQL语句的结果数据集,每个游标区都有一个名字,通过移动游标名代表的指针来访问数据集中的数据
2、使用游标须要经历五个步调:
- 界说游标:DECLARE
- 打开游标:OPEN
- 逐行提取游标集中的行:FETCH
- 关闭游标:CLOSE
- 开释游标:DEALLOCA
3、游标的界说
DECLARE <游标名>[SCROLL] CURSOR
FOR<SELECT语句>
[for[read only / update{of<列名>}]
SCROLL:说明所声明的游标可从前滚,后滚,可使用全部的提取选项。如省略,则只能使用 NEXT 提取选项。
READ ONLY 表示当前游标集中的元组仅可以查询,不能修改;
UPDATE {OF <列名>}表示可以对当前游标集中的元组举行更新操作。如果有OF <列名>,表示仅可以对游标集中指定的属性
如:界说一个能够存放sc表数据的游标
4、游标的打开
游标界说后,如果要使用游标,必须先打开游标。
打开游标操作表示:
- 系统按照游标的界说从数据库中将数据检索出来,放在内存的游标集中(如果内存不够,会放在临时数据库中)
- 为游标集指定一个游标,该游标指向游标集中的第1个元组
格式:Open 游标名;
打开游标后,可以使用全局变量@@CURSOR_ROWS查察游 标集中数据行的数目。全局变量@@CURSOR_ROWS中保存着最后打开的游标中的数据行数。当其值为0时,表示没有游标打开; 当其值为m(m为正整数)时,游标已被完全填充,m是游标中的数据行数。
例:界说游标XS_CUR3,然后打开该游标,输出其行数。
- DECLARE XS_CUR3 CURSOR SCROLL
- FOR
- SELECT 学号,姓名,总学分
- FROM XSB
- FOR UPDATE OF 总学分
- OPEN XS CUR3
- SELECT '游标XS_CUR3数据行数'=@@CURSOR_ROWS
复制代码 5、游标的读取
- FETCH [ NEXT | PRIOR | FIRST | LAST | ABSOLUTE {n| @nvar | RELATIVE {n|@nvar] FROM {游标} [INTO @变量名,...]
- NEXT |PRIOR|FIRST |LAST:说明读取数据的位置。
1.Next:读取当前行的下一行,并使其置为当前行。如 fetch next 为对游标的第一次提取操作,则读取第一行,next 为默认值。
2.prior:读取当前行的前一行,并使其置为当前行。如是第一次操作,则无值返回,游标被置于第一行之前。
3.first :读取第一行,并使其置为当前行。
4.last:读取最后一行,并使其置为当前行。
5. ABSOLUTE {n| @nvar } | RELATIVE {n| @nvar} : 给出读取数据的位置与游标头或当前位置的关系,此中n必须 为整型常量,@nvar必须smallint、tinyint或int型
例:从游标XS_CURI中提取数据。设该游标已经声明并打开。
FETCH语句的执行状态保存在全局变量 @@FETCH_STATUS中,其值为0表示上一个FETCH执行 成功;为-1表示所要读取的行不在结果集中;为2表示被提取的行已不存在(已被删除)。
比方,接着上例继承执行如下语句:(此时游标在倒数第三行)
- FETCH RELATIVE 3 FROM XS_CUR2
- SELECT'FETCH执行情况'= @@FETCH_STATUS
复制代码 执行结果为:-1,此时游标已出界
6、游标的关闭
- 关闭游标 CLOSE 游标
- 开释游标:游标关闭后,其界说仍在,须要时可用OPEN语句打开它再使用。若确认游标不再须要,就要开释其界说占用的系统空间,即删除游标。DEALLOCATE 游标名
7、游标的使用
[例] 创建一个游标,逐行显示选修了《计算机原理》课程的学生姓名、相应成绩和该课程的均匀分。
①选修《计算机原理》课程的同砚可能不止一个,须要使用
游标查询选修该门课程的学生姓名和相应的选课成绩。
界说游标为:
- DECLARE myCur CURSOR FOR
- SELECT studentName, score
- FROM Student a, Course b, Score C
- WHERE a.studentNo=c.studentNo AND b.courseNo=c.courseNo
- ANDcourseName='计算机原理'
复制代码 ②要得到该课程的均匀分,必须首先计算选课人数和总分
•界说计数器和累加器变量@countScore、@sumScore,初始值为0
- DECLARE @countScore smallint,@sumScore int
- SET @countScore=0
- SET @sumScore=0
复制代码 3、界说两个变量@sName 和 @score,用于吸收游标集中当前游标中的学生姓名和相应的选课成绩
- DECLARE @sName varchar(20), @score tinyint
复制代码 4、由于 FETCH 下令每次仅从游标集中提取一条记录,必须通过一个循环来重复提取,直到游标集中的全部记录被提取
- 全局变量@@FETCHL_STATUS 用于判定是否精确地从游标集中提取到了记录;
- @@FETCH_STATUS=0 表示已经精确提取到了游标记录;
循环语句为: ⑤ 在循环体内:
•首先显示所提取到的学生姓名和相应的选课成绩,使用语句:
- SELECT @sName 学生姓名,@score 课程成绩
复制代码 其次,计数器 @countScore 举行计数,并将提取到的成绩累加到变量 @sumScore 中。语句为:
- SET@sumScore=@sumScore+@score
- SET @countScore=@countScore+1
复制代码
提取下一条游标记录:
- FETCH myCur INTO @sName, @score
复制代码 •重复⑤,直到全部游标记录处理
⑥处理完全部游标记录后:
关闭和开释游标
•对计数器@countscore举行判定:
如果为0,表示没有同砚选修,其均匀分为0;
香则,均匀分等于总分除以选课人数。
⑦程序如下:
/*界说变量及赋初值*/ DECLARE @sName varchar(20), @score tinyint
DECLARE@sumScore int, @countScore smallint
SET @sumScore=0
SET@countScore=0
--界说游标
DECLARE myCur CURSOR FOR
SELECT studentName, score
FROM Student a, Course b, Score c
WHERE a.studentNo=c.studentNo AND b.courseNo=c.courseNo
ANDcourseName='计算机原理'
OPEN myCur
-打开游标
--获取当前游标的值放到变量@sName和@score中
FETCH myCur INTO @sName, @score
WHILE (@@FETCH_STATUS=0)
BEGIN
-显示变量@sName和@score中的值
SELECT@sName学生姓名,@score课程成绩
SET@sumScore=@sumScore+@score
--计算总分
SET @countScore=@countScore+1
--计算选课人数
FETCH myCur INTO@sName, @score
--获取下一个游标值
END
IF @countScore>0
SELECT@sumScore/@countscore课程均匀分
ELSE
SELECT0.00课程均匀分
CLOSE myCur
-关闭游标
DEALLOCATE myCur
-开释游标
二、存储过程
1、存储过程概述
•存储过程和函数一样,是命名的语句块,它们被编译后保存在数据库中,可反复调用,并在 DBMS上得到执行。
存储过程的优点
- 经编译和优化后存储在数据库服务器中,运行效率高
- 有利于集中控制
- 实现一定程度的安全性保护
- 存储过程存放在数据库中,且在服务器端运行;
对于不答应用户直接操作的表或视图,可通过调用存储过程来间接地访问这些表或视图,达到一定程度的安全性;
- 这种安全性缘于用户对存储过程只有执行权限,没有查察权限;
- 拥有存储过程的执行权限,主动获取了存储过程中对相应表或视图的操作权限;
- 这些操作权限仅能通过执行存储过程来实现,一旦脱离存储过程,也就失去了相应操作权限。留意:对存储过程只需授予执行权限,不需授予表或视图的操作权限
- 特别得当统计和查询操作
- 一样平常统计和查询,尤其是期末统计,往往涉及数据量大、表多,若在客户端实现,数据流量和网络通信量较大;
许多环境下,管理信息系统的设计者,将复杂的查询和统计用存储过程来实现,免去客户端的大量编程
- 淘汰网络通信量:存储过程仅在服务器端执行,客户端只吸收结果;
- 由于存储过程与数据一样平常在一个服务器中,可淘汰大量的网络通信量。
- 使用存储过程前,首先要创建存储过程。可对存储过程举行修改和删除。
- 创建存储过程后,必须对存储过程授予执行 EXECUTE 的权限,否则该存储过程仅可以供创建者执行。
2、存储过程的创建
- 存储过程的创建
- CREATE{PROC|PROCEDURE}过程名[{@参数1 数据类型,}
- [OUT | OUTPUT ]1/*定义参数的属性*/
- [...n]AS 语句块/* 定义所需要执行的操作*/
复制代码
- 存储过程可不带参数,参数可以是变量、常量和表达式;
- [OUT |OUTPUT]:表示参数为输出参数,输出参数可以从存储过程返回信息。缺省时表示输入参数
- 如果存储过程的输出参数取集合值,则该输出参数不在存储过程的参数中界说,而是在存储过程中界说一个临时表来存储该集合值。
- 临时表的表名前加一个#符号,如#myTemp
- 在存储过程尾部,使用语句:
SELECT * FROM #myTemp
将结果集合返回给调用者。
- 存储过程结束后,临时表主动被删
- 留意:
- 用户界说的存储过程只能在当前数据库中创建;
- 一个存储过程最大不能超过128MB。若超过128MB,可将超出的部门编写为另一个存储过程,然后在存储过程中调用
例:创建一个存储过程,查询学号为“2011001”的学生的选课信息
- CREATE PROCEDURE class_studied_nopar
- AS
- SELECT *
- FROM SC
- WHERE Sno= '2011001';
复制代码 例:创建一个存储过程,查询用户指定学号的学生选课信息
- CREATE PROCEDURE class_studied_par @sno varchar(7)
- AS
- SELECT *
- FROM SC
- WHERE Sno = @sno;
复制代码 例:创建一个存储过程,查询并返回用户指定学号的学生的均匀成绩
- CREATE PROCEDURE studentaveragescore @sno varchar(7) , @avg_score decimal output
- AS
- SELECT @avg_score = avg(grade)
- FROM SC
- GROUP BY sno
- HAVING sno = @sno
复制代码 3、存储过程的应用与实践
例:输入某个同砚的学号,统计该同砚的均匀分,并返回该同砚的姓名宁静均分。
分析:该过程涉及三个参数:
- 一个输入参数,设为 @sNo,用于吸收某同砚的学号;
- 两个输出参数,用于返回查询到的同砚姓名宁静均分,设为
@sName #H@avg
- 实现方法一:
- 用一个查询,根据输入参数 @sNo,查询出该同砚的姓名并放到输出参数 @sName 中
- 由于在学生表中学号是唯一的,使用下令:
- SELECT @snName = studentName
- FROM Student
- WHERE studentNo=@sno
复制代码 - 用另一个查询,根据输入参数 @sNo,查询出该同砚的选课均匀分并放到输出参数 @avg 中
- 由于该同砚的均匀分也只有一个,使用下令:
- SELECT @avg=AVG(score)
- FROM Score
- WHERE studentNo=@sno
复制代码 存储过程为:
- CREATE PROCEDURE proStudentByNo21 @sNo char(7), @sName
- varchar(20) OUTPUT, @avg numeric(5, 1) OUTPUT
- AS
- BEGIN
- --查询同学的姓名放入输出参数@sName中
- SELECT @sName=studentName
- FROM Student
- WHERE studentNo=@sNo
- --查询同学选课的平均分放入输出参数@avg中
- SELECT@avg=AVG(score)
- FROM Score
- WHERE studentNo=@sNo
- END
复制代码- 实现方法二:
- 用一个查询,根据输入参数 @sNo,查询出该同砚的姓名并放到输出参数 @sName 中,其下令同方法一
- 界说一个游标,根据输入参数@sNo,查询该同砚全部的选课记录,使用下令:
DECLARE myCur CURSOR FOR SELECT score
FROM Score
WHERE studentNo=@sNo
- 界说局部变量 @score,用于吸收从游标集中获取的成绩;
- 界说局部变量@count,用于统计选课门数;
- 界说局部变量 @sum,用于对成绩举行累加
- 其存储过程为:
- CREATE PROCEDURE proStudentByNo22(@sNo char(7), @sName varchar (20) OUTPUT, @avg numeric(5, 1) OUTPUT)
- AS BEGIN
- DECLARE @score tinyint, @count tinyint,@sum int
- -查找姓名,并放入到输出参数@sName中
- SELECT@sName=studentName
- FROM Student
- WHERE studentNo=@sNo
- --变量赋初值
- SET@count=0
- SET@sum=0
- -统计学生选课门数@count和总分@sum,使用游标:
- DECLARE myCur CURSOR FOR
- SELECT score
- FROM Score
- WHERE studentNo=@sNo
- OPEN myCur
- FETCH myCur INTO @score
- WHILE (@@FETCH_STATUS=0)
- BEGIN
- SET @count=@count+1
- SET @sum=@sum+@score
- CLOSE myCur
- DEALLOCATE myCur
- IF @count>0
- SELECT @avg=@sum/@count
- ELSE
- SELECT @avg=0
- END
复制代码 其实就是不使用avg函数然后通过游标遍历score
例:输入某同砚的学号,使用游标统计该同砚的均匀分, 并返回均匀分,同时逐行显示该同砚的姓名、选课名称和选课成绩。
- CREATE PROCEDURE proStudentAvg{@sNo char(7), @avg numeric(6, 2) OUTPUT)
- AS
- BEGIN
- DECLARE @sName varchar(20), @cName varchar (20)
- DECLARE @grade tinyint, @sum int, @count tinyint
- SELECT @sum=0, @count=0
- -定义、打开、获取游标
- DECLARE curGrade CURSOR FOR SELECT studentName, courseName, score FROM Score a, Student b, Course c
- WHERE b.studentNo=@sNo
- AND a.studentNo=b.studentNo AND a.courseNo=c.courseNo
- OPEN curGrade
- FETCH curGrade INTO @sName,@cName,@grade
- WHILE (@@FETCH_STATUS=0)
- BEGIN
- --业务处理
- SELECT@SName,@cName,@grade --输出
- SET @sum=@sum+@grade
- SET @count=@count+1
- FETCH curGrade INTO @sName, @cName,@grade
- END
复制代码
- 本例使用了 SELECT 语句来显示变量的值,即
SELECT @sName, @cName, @grade
- 由于存储过程仅在服务器端执行,其显示的内容只在服务器端出现,并不返回给客户端,这样的输出结果是没有价值的。
- 显示内容在调试存储过程时有作用,一旦过程调试精确,使用存储过程的修改下令将显示内容
当然,存储过程中的游标也可以通过嵌套来达到更强的功能,这里不多分析
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |