SqlServer:存储过程
存储过程#
存储过程(Stored Procedure)简称过程,由一系列SQL语句构成完成一定的功能的程序段,通过过程名调用并执行。在 SqlServer 中存放在数据库的“可编程性”组件中,与表和视图的级别相同。存储过程是由流程控制和 SQL 语句组成的,允许用户声明变量,可以调用系统函数,经编译后存储在数据库服务器中。存储过程可以接收输入参数,也可以将运行结果带出过程,返回执行存储过程的状态值,还可以嵌套调用。由于存储过程在服务器运行,且运行后会保存在缓存中,因此可以提高运行效率。
存储过程分为三类,分别是系统存储过程、用户自定义存储过程和扩展存储过程。
存储过程类型 | 说明 |
---|---|
系统存储过程 | 系统自动创建的系统存储过程,用于显示各种参数等,以 “sp_” 为前缀 |
自定义存储过程 | 由用户为完成某一特定功能而编写的存储过程,名称不能以 “sp_” 为前缀 |
扩展存储过程 | 是对动态链接库(DLL)函数的调用,前缀名是 “XP_” |
创建存储过程的步骤是:
- 检验存储过程名是否存在;
- 编写存储过程中的 SQL 语句;
- 用创建存储过程的语法创建存储过程。
SQL 语句#
建立存储过程前需要确定其功能,存储过程的调用可以是无参数调用或有参数调用,可以有返回值或者没有参数返回。建立存储过程的命令格式是:
CREATE PROCEDURE 存储过程名
[WITH ENCRYPTION]
[@参数名 类型 [ = 默认值][OUTPUT]][,-n ]
AS SQL语句
参数 | 说明 |
---|---|
PROCEDURE | 存储过程名 |
WITH ENCRYPTION | 将存储过程的代码加密 |
@参数名 类型 | 接收指定的实际参数及类型 |
OUTPUT | 表示参数是输出参数,若无此项则参数是输入参数 |
SQL 语句 | 是构造存储过程的 SQL 语句,如果包括多条命令可以用 BEGIN…END 代码块 |
调用存储过程的方式有以下 2 种:
存储过程名 [参数值] --存储过程名是批处理的第 1 条语句
EXECUTE 存储过程名 [参数值] --存储过程名不是批处理的第 1 条语句
存储过程样例#
样例一#
此时有成绩表 Score 和课程表 Course,表中具有以下字段和记录。
用户输入某一门课程的名称,就可统计出该课程各分数段分布的人数。首先建立排名表:
CREATE TABLE Rank(
division char(20),
sub_sum int
);
INSERT INTO Rank(division) VALUES('[0,60)'),('[60,70)'),('[70,80)'),('[80,90)'),('[90,100]');
接着创建存储过程。
CREATE PROCEDURE printcourse @pcname char(20)
AS
DECLARE @pcno char(20), @pcount int, @count int
set nocount on
SELECT @count = COUNT(*) FROM Course WHERE Cname = @pcname
IF(@count = 0)
BEGIN
RAISERROR('您输入的课程不存在,请重新输入!', 16, 1)
RETURN
END
--查找 @pcname 对应的课程号
SELECT @pcno = Score.cno FROM Course, Score WHERE Course.Cno = Score.Cno AND Course.Cname = @pcname
--统计不及格人数,并更新 Rank 表
SELECT @pcount = COUNT(*) FROM Score WHERE Degree < 60 AND Cno = @pcno
UPDATE Rank SET sub_sum = @pcount WHERE division = '[0,60)'
SELECT @pcount = COUNT(*) FROM Score WHERE Degree >= 60 AND Degree < 70 AND Cno = @pcno
UPDATE Rank SET sub_sum = @pcount WHERE division = '[60,70)'
SELECT @pcount = COUNT(*) FROM Score WHERE Degree >= 70 AND Degree < 80 AND Cno = @pcno
UPDATE Rank SET sub_sum = @pcount WHERE division='[70,80)'
SELECT @pcount = COUNT(*) FROM Score WHERE Degree >= 80 AND Degree < 90 AND Cno = @pcno
UPDATE Rank SET sub_sum = @pcount WHERE division='[80,90)'
SELECT @pcount = COUNT(*) FROM Score WHERE Degree >= 90 AND Degree <= 100 AND Cno = @pcno
UPDATE Rank SET sub_sum = @pcount WHERE division = '[90,100]'
最后尝试执行该存储过程。
EXEC printcourse '计算机导论'
SELECT * FROM Rank
样例二#
统计某一门课的平均成绩,存储过程可带有一个字符型参数值,接受用户输入的课程名称。一个输出参数(用 output 声明)用于存放返回给调用者的这门课程的平均成绩)。
CREATE PROCEDURE printavg_course @pcname char(20), @pavg int output
AS
DECLARE @pcno char(20)
SET NOCOUNT ON
SELECT @count = COUNT(*) FROM Course WHERE Cname = @pcname
IF(@count = 0)
BEGIN
RAISERROR('您输入的课程不存在,请重新输入!', 16, 1)
RETURN
END
--最关键的 2 行
SELECT @pcno = Score.cno FROM Course, Score WHERE Course.Cno = Score.Cno AND Course.Cname = @pcname
SELECT @pavg = AVG(Score.Degree) FROM Score WHERE Cno = @pcno
PRINT RTrim(@pcname) + '的平均成绩为:' + CAST(@pavg AS char(5))
运行该存储过程。
DECLARE @pavg int
EXEC printavg_course '操作系统', @pavg output
Select @pavg int
样例三#
在 Course 表中查询学生的学号、课程号和成绩,但是要将学生选课成绩从百分制改为等级制,即 A、B、C、D、E 五级。
CREATE PROCEDURE printclass_degree
AS
SELECT Sno, Cno, Degree,
CASE
WHEN Degree < 60 THEN '不及格'
WHEN Degree >= 60 AND Degree < 70 THEN '及格'
WHEN Degree >= 70 AND Degree < 80 THEN '中'
WHEN Degree >= 80 AND Degree < 90 THEN '良'
WHEN Degree >= 90 AND Degree <= 100 THEN '优'
ELSE '成绩为空!'
END AS 'Degree Classified'
FROM Score
运行该存储过程。
EXEC printclass_degree
样例四#
表 Course 增加两列,分别是课程选修最大人数(mn ,默认50)和当前人数(cn ,默认0)。
某学生没有选过某课程,要选某课程且没有超过课程最大人数时,可以选择该课程,当前选课人数加1,并在成绩 Score 表中增加对应的该生该课程的成绩为 0 记录。否则,提示该课程选课人数已满,不能选课。
CREATE PROCEDURE cs @sno char(3), @cno char(5)
AS
DECLARE @mn INT, @cn INT, @count INT
SET @count = (SELECT count(Sno) FROM Score WHERE Sno = @sno AND Cno = @cno)
IF(@count = 1)
BEGIN
RAISERROR('该学生已经选过这门课',16,1)
END
ELSE
BEGIN
SELECT @mn = mn FROM Course WHERE Cno = @Cno
SET @count = (SELECT count(Sno) FROM Score WHERE Cno = @Cno)
IF(@count >= @mn)
BEGIN
RAISERROR('该课程已达到最大选课人数',16,1)
END
ELSE
BEGIN
UPDATE Course SET cn = @count + 1 WHERE Cno = @cno
INSERT INTO Score(Sno, Cno, Degree) VALUES(@sno, @cno, 0)
RAISERROR('学生选课成功',16,1)
END
END
运行该存储过程。
EXEC cs '101', '3-245'
SELECT * FROM Score
SELECT * FROM Course
EXEC cs '101', '3-235'
某学生选了某课程后要退选,该课程的当前选课人数减 1 并删除其对应的成绩。
CREATE PROCEDURE csd @sno char(3), @cno char(5)
AS
DECLARE @mn INT, @cn INT, @count INT
SET @count = (SELECT count(Sno) FROM Score WHERE Sno = @sno AND Cno = @cno)
IF(@count = 0)
BEGIN
RAISERROR('该学生没有选过这门课',16,1)
END
ELSE
BEGIN
SELECT @cn = cn FROM Course010 WHERE Cno = @Cno
UPDATE Course SET cn = @cn - 1 WHERE Cno = @cno
DELETE Score WHERE Sno = @sno AND Cno = @cno
RAISERROR('学生退课成功',16,1)
END
运行该存储过程。
EXEC csd '101', '3-245'
SELECT * FROM Score
SELECT * FROM Course
EXEC csd '101', '3-245'
CREATE PROCEDURE cx @sno char(3), @cno char(5)
AS
DECLARE @mn INT, @cn INT, @count INT
SET @count = (SELECT count(Sno) FROM Score WHERE Sno = @sno AND Cno = @cno)
IF(@count = 0)
BEGIN
RAISERROR('该学生没有选过这门课',16,1)
END
ELSE
BEGIN
SELECT * FROM Score WHERE Cno = @cno AND Sno = @sno
END
运行该存储过程。
EXEC cx '101', '3-245'
参考资料#
《SqlServer 2014 数据库技术实用教程》,胡伏湘、肖玉朝 主编,清华大学出版社
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2020-06-02 网络层——路由选择算法