任务描述
本关任务:学习 SQL Server 中存储过程的创建和使用。
相关知识
存储过程提供了很多 T-SQL 语言没有的高级特性,其传递参数和执行逻辑的能力,为处理各种复杂任务提供了支持。并且,由于存储过程是经过编译后,存储在服务器上的,这减少了执行过程中的传输带宽和执行时间。相反,如果使用 T-SQL ,则每次需要经过传输,再编译和执行。
什么是存储过程
存储过程是 SQL Server 中一个非常重要的数据库对象,它实际是一组为了完成特定功能的 T-SQL 语句集合。存储过程经编译后,存储在数据库中,用户通过指定存储过程的名称,并给出相应的参数,就可以对其进行执行。
SQL Server 中的存储过程具有如下特点:
- 能够包含执行各种数据库操作的语句,并且可以调用其他的存储过程;
- 能够接收输入参数,并以输出参数的形式,将多个数据值返回给调用程序或批处理;
- 向调用程序或批处理,返回一个表明成功或失败(及失败原因)的状态;
- 存储过程经过编译后,存储在数据库中,用户通过使用存储过程的名字,并指定参数来执行它。
存储过程不同于函数,存储过程不返回取代其名称的值,也不能直接在表达式中使用。
存储过程的类型
SQL Server 包含多种可用的存储过程,主要包括用户定义存储过程、扩展存储过程和系统存储过程。 ######用户定义存储过程 存储过程是指封装了可重用代码的模块或者例程。存储过程可以接收输入参数、向客户端返回表格或者标量结果和消息、调用数据定义语言( DDL )和数据操作语言( DML ),然后返回输入参数。 在 SQL Server 中,用户定义的存储过程有两种类型,即 T-SQL 和 CLR 。
- T-SQL 存储过程是指保存的 T-SQL 语句集合,可以接收和返回用户提供的参数。存储过程也可能从数据库向客户端应用程序返回数据。
- CLR 存储过程是指针对 .NET Framework 公共语言运行时方法的引用,可以接收和返回用户提供的参数。它们在 .NET Framework 程序集中,是作为类的公共静态方法来实现的。
扩展存储过程
扩展存储过程以在 SQL Server 环境外执行的动态链接库( DLL )来实现。扩展存储过程通过前缀 xp_ 来标识,它们以与系统存储过程相似的方式来执行。
系统存储过程
系统存储过程主要存储在 master 数据库中,并以 sp_ 为前缀,并且系统存储过程主要是从系统表中获取信息,从而为系统管理员 SQL Server 提供支持。通过系统存储过程, SQL Server 中的许多管理性或者信息性的活动,都可以被顺利有效地完成。
创建存储过程
在 SQL Server 中,使用 CREATE PROCEDURE 语句创建存储过程,具体的语法格式如下所示。
CREATE { PROC | PROCEDURE } procedure_name [ ; number ]
[ { @parameter data_type }
[ VARYING ] [ = default ] [ OUT | OUTPUT ] [READONLY]
[ WITH {RECOMPILE|ENCRYPTION|RECOMPILE,ENCRYPTION}]
[ FOR REPLICATION ]
AS { [ BEGIN ] sql_statement [;] [ ...n ] [ END ] }
简单介绍个参数的含义。
- procedure_name 用于指定存储过程的名称;
- number 用于指定对同名的过程分组;
- @parameter 用于指定存储过程中的参数;
- data_type 用于指定参数的数据类型;
- VARYING 用于指定作为输出参数支持的结果集,仅适用于游标参数;
- default 用于指定参数的默认值;
- OUTPUT 用于指定参数是输出参数;
- RECOMPILE 用于指定数据库引擎不缓存该过程的计划,该过程在运行时编译;
- ENCRYPTION 用于指定 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE 语句文本的条目;
- FOR REPLICATION 用于指定不能在订阅服务器上执行为复制创建的存储过程;
- sql_statement 要包含在过程中的一个或多个 T-SQL 语句。
在命名自定义存储过程时,尽量不要使用 sp_ 作为名称前缀,避免与系统存储过程冲突。如果指定的名称与系统存储过程相同,由于系统存储过程优先级高,那么自定义的存储过程永远也不会执行。 ######创建简单存储过程 从 studentdb 数据库中获取学生学号、姓名和性别的存储过程。语句如下所示:
CREATE PROCEDURE proc_getInfos
AS
BEGIN
SELECT sno '学号', sname '姓名', sex '性别' from student
END
创建带计算函数的存储过程
统计 studentdb 数据库中,男同学个数的存储过程。语句如下:
CREATE PROCEDURE proc_count_male
AS
BEGIN
SELECT COUNT(*) AS '男同学' frome student where sex='男'
END
创建带输入参数的存储过程
根据用户输入的姓名,得到相应的信息的存储过程。语句如下:
CREATE PROCEDURE proc_select_where
@name varchar(50)
AS
BEGIN
SELECT * from student where sname=@name
END
创建带输出参数的存储过程
创建一个存储过程,根据用户输入的年龄,返回大于输入年龄的学生有多少。语句如下:
CREATE PROCEDURE proc_select_ret
@age int,
@age_count int output
AS
BEGIN
SELECT @age_count=COUNT(*) from student where age>@age
END
执行存储过程
在 SQL Server 中,可以使用 EXEC 或 EXECUTE 语句执行存储过程。 ######执行不带参数的存储过程
EXEC proc_getInfos
执行带参数的存储过程
EXEC proc_select_where '张三'
执行带输入输出参数的存储过程
DECLARE @age_ int=19;
DECLARE @count int;
EXEC proc_select_ret @age_, @count output
select '该班一共有'+LTRIM(STR(@count))+'人年龄大于'+LTRIM(STR(@age_));
编程要求
我们已经为你建好了数据库与数据表,并添加了相应的数据内容。 你只需:
- 补全右侧代码片段中 create proc_student_info 下的 Begin-End 区域间的代码,实现从表中查询所有学生基本信息的存储过程(存储过程名称一定要为 proc_student_info ,测试代码将调用 proc_student_info 存储过程,下面类似);
- 补全右侧代码片段中 create proc_sno 下的 Begin-End 区域间的代码,创建一个带参数的存储过程,输出指定学号的学生信息;
- 补全右侧代码片段中 create proc_add 下的 Begin-End 区域间的代码,创建一个带参数的存储过程,根据指定参数增加学生信息,如果学生编号已经存在则不能增加(调用此存储过程时,会依次填充各个字段值,请注意 insert 时,参数顺序与表字段的顺序一致);
- 补全右侧代码片段中 create student_del 下的 Begin-End 区域间的代码,创建一个带参数的存储过程,删除指定学号的学生信息。若成功,则输出 successfully deleted ;若没有该学号,则输出 No such student 。
表 student 的字段类型除了 birthday 是 date 类型,其余均为 varchar 类型,表内容如下:
测试说明
本关涉及到的测试文件是 step1.sh ,平台将运行用户补全的 step1.sql 文件,得到数据,然后执行以下操作:
-
将得到的数据与答案比较,判断程序是否正确;
-
如果操作正确,你将得到如下的结果:
实验代码
USE studentdb
go
SET NOCOUNT ON
go
--********** create proc_student_info **********--
--********** Begin **********--
create proc proc_student_info
as
Begin
select* from student
End
--********** End **********--
go
exec proc_student_info
go
--********** create proc_sno **********--
--********** Begin **********--
create proc proc_sno
@sno varchar(50)
as
Begin
select * from student where sno = @sno
End
--********** End **********--
go
exec proc_sno '1001'
go
--********** create proc_add **********--
--********** Begin **********--
create proc proc_add
@sno varchar(50),
@sname varchar(50),
@sex varchar(10),
@date date,
@dis varchar(50),
@school varchar(50)
as
Begin
if EXISTS(SELECT * FROM student WHERE sno=@sno)
print 'Already have a primary key '+@sno
else
insert into student values(@sno,@sname,@sex,@date,@dis,@school)
End
--********** End **********--
go
exec proc_add '1004','HMM','female','2019-6-2','English','national school'
go
exec proc_student_info
go
--********** create student_del **********--
--********** Begin **********--
create proc student_del
@sno varchar(50)
as
Begin
if EXISTS(select * from student where sno=@sno)
Begin
delete from student where sno = @sno
print'successfully deleted'
End
else
print'No such student'
End
--********** End **********--
go
exec student_del '1001'
go
exec proc_student_info
go