1.就是预先编译sql语句的集合
2.可以代替传统的逐条执行SQL语句的方式
3.可包含查询,插入,删除,更细等操作的一系列SQL语句
4.存储在sql server中
5.通过名称和参数执行
6.可带参数,也可返回结果
7.可包含数据操纵语句,变量,逻辑控制语句
执行速度更快:因为存储过程在创建时就被编译,每次执行都不需要编译,而SQL语句的每一次执行都需要编译
允许模块化程序设计:存储过程一旦被创建,以后即可在程序中调用任意多次,这可以改进应用程序的可维护性,并允许应用程序统一访问数据库提高系统的安全性:存储过程在数据库中,用户只需提交存储过程名称就可以直接执行,避免了攻击者非法截取SQL代码获得用户数据的可能性
减少网络流通性:一个需要几百SQL语句代码的操作可以通过一条执行过的程序代码来执行,而不需要在网络中发送百行代码
重要的优点是:安全,执行速度快
创建存储过程,通常以usp_开头(用的比较多)
不带参数的存储过程的创建与调用:
--常用的系统存储过程
use master
go
execute sp_databases
exec sp_renamedb @dbname='Demo',@newname='myDemo'
exec sp_renamedb 'myDemo','Demo'
--查看Post表中的所有信息
use Demo
go
exec sp_help Post
--常用的扩展存储过程:
use master
go
exec sp_configure 'show advanced option',1 --能够启动xp_cmdshell高级配置
go
reconfigure
go
exec sp_configure 'xp_cmdshell',1 --打开xp_cmdshell,可以调用SQLserver之外的系统命令
--使用xp_cmdshell 在D盘创建myFile的文件夹
exec xp_cmdshell 'mkdir d:\myFile',no_output --[no_output]是否输出返回信息
go
--如果SQLserver版本高的话,执行xp_cmdshell这个扩展存储过程的时候会报以下的错误:
--SQL Server 阻止了对组件 'xp_cmdshell' 的 过程 'sys.xp_cmdshell' 的访问,
--因为此组件已作为此服务器安全配置的一部分而被关闭。
--系统管理员可以通过使用 sp_configure 启用 'xp_cmdshell'。
--有关启用 'xp_cmdshell' 的详细信息,请参阅 SQL Server 联机丛书中的 "外围应用配置器"。
--创建不带参数的存储过程:
use E_Market
go
--题目:
/*
查看xiangxiang所购买的商品信息,包括用户名,付款方式,购买数量,商品的名称
商品的类别
*/
--检测是否存在要创建的存储过程,如果存在将其删除
if exists (select * from sysobjects where name='usp_GetCommodityInfo')
drop proc usp_GetCommodityInfo
go
--删除之后要加go因为create proc 是批处理仅有的语句
create proc usp_GetCommodityInfo
as
select O.UserId as 用户号 ,payWay as 付款方式 ,O.Amount as 购买数量,
C.CommodityName as 商品名称,S.SortName as 类别名称 from OrderInfo as O
inner join CommodityInfo as C on O.CommodityId=C.CommodityId
inner join CommoditySort as S on S.SortId=C.SortId
where O.UserId='xiangxiang'
go --存储过程的结束
--如何使用不带参数的存储过程
exec usp_GetCommodityInfo
go
带输入参数的存储过程的创建与调用:
--创建带输入参数的存储过程:
/*
题目:查询指定的用户在指定的时间段内的下单信息,
如果结束日期没有指定的话,那么查询的是到今天为止的下单信息
*/
use E_Market
go
if exists(select * from sysobjects where name='usp_GetOrderInfo')
drop proc usp_GetOrderInfo
go
create proc usp_GetOrderInfo
@startDate datetime,--开始时间
@endDate datetime=null,--结束时间
@userId varchar(20) =null --指定用户
as
if @endDate is null --判断日期是否为空
begin
set @endDate=GETDATE()--赋当前日期
end
if @userId is null--查询指定时间段内订单的所有信息
begin
select C.CommodityName as 商品名称,s.SortId as 类别名称,o.UserId as 用户名,o.OrderTime as 下单时间 from OrderInfo as O
inner join CommodityInfo as C on O.CommodityId=C.CommodityId
inner join CommoditySort as S on C.SortId=S.SortId
where O.OrderTime between @startDate and @endDate
end
else --查询指定用户指定时间段内的所有信息
begin
select C.CommodityName as 商品名称,s.SortId as 类别名称,o.UserId as 用户名,o.OrderTime as 下单时间 from OrderInfo as O
inner join CommodityInfo as C on O.CommodityId=C.CommodityId
inner join CommoditySort as S on C.SortId=S.SortId
where O.OrderTime between @startDate and @endDate
and o.UserId=@userId
end
go--存储过程结束
--如何调用带参数的存储过程
--1)结束日期与用户都使用默认值
--指定了开始时间,查询的是从开始时间到今天的所有订单信息
exec usp_GetOrderInfo '2018-05-02'
--2.结束日期不为空,从开始时间到结束时间的所有信息
--隐式调用,参数顺序必须与创建存储过程的参数顺序完全相同
exec usp_GetOrderInfo '2018-05-02','2018-05-10','xiangxiang'
--3.显示调用,对参数顺序无要求,但是如果有参数中一个写了@名称=值的形式,
--之后的参数都必须写成@名称=值,默认值可以使用default代替
exec usp_GetOrderInfo @UserId ='xiangxiang',@startDate='2018-05-02',
@endDate=default
--显示调用时的@userId,@startDate,@endDate是存储过程定义时的参数
--要和上面声明的参数相同
--4.可以通过声明变量来调用
declare @d1 datetime,@d2 datetime,@uid varchar(20)
set @d1='2018-05-02'
set @d2='2018-05-19'
set @uid='xiangxiang'
exec usp_GetOrderInfo @d1,@d2,@uid
--除了显示调用之外,要求参数位置必须与存储过程定义时的顺序相同
带输出参数的存储过程的创建与调用:
--创建带输入输出参数的存储过程
/*
题目:向母婴用品这个类别添加一种商品,
要求成功后把商品的编号返回,编号输出
*/
use E_Market
go
if exists (select * from sysobjects where name='usp_InsertCommodity')
drop proc usp_InsertCommodity
go
create proc usp_InsertCommodity
@SortName varchar(50), --类别别名
@CommodityName varchar(100), --商品名称
@inPrice money, --进货价
@outPrice money, --销售价
@Amount int , --库存量
@CommodityId int output --要输出的参数:商品编号
as
--根据输入的类别名称查询类别编号是否存存
declare @SortId int
select @SortId=SortId from CommoditySort where SortName =@SortName
--判断类别名称是否正确,如@SortId 为空类别名称出错,否则类别正确
if @SortId is null
begin
print '对不起,输入的类别不存在'
return --后面的代码无条件退出创建存储过程
end
--向商品信息表插入数据
insert into CommodityInfo(SortId ,CommodityName,InPrice,OutPrice,Amount)
values(@SortId,@CommodityName,@inPrice,@outPrice,@Amount)
if @@ERROR >0 --判断错误号时候大于0,如果大于0说明插入有误
begin
print '插入信息失败'
return
end
set @CommodityId=@@IDENTITY --编号,@@IDENTITY系统可以获得我们的标识列
go
--使用带输入输出参数的存储过程
--1.声明变量来调用(隐式调用,要求参数定义的顺序于声明时的相同)
declare @sortName varchar(50),@commodityName varchar(100),
@inprice money,@outprice money,@amount int,@commodityId int
select @sortName='母婴用品',@commodityName='星飞帆1段',@inprice=200,
@outprice=245,@amount=1000
EXEC usp_InsertCommodity @sortName,@commodityName,@inprice,@outprice,@amount,@commodityId output
print '添加商品成功,商品编号为:'+convert(varchar(5),@commodityId) --因为商品编号是int类型的,所以需要强制类型转换
go
--检查插入的数据
select * from CommodityInfo
带返回值的存储过程的创建与调用:
use E_Market--创建带返回值的一个存储过程
go
/*
向母婴用品中添加一条商品信息
*/
use E_Market
go
if exists(select * from sysobjects where name='usp_insertCommodityReturn')
drop proc usp_insertCommodityReturn
go
create proc usp_insertCommodityReturn
@sortName varchar(50),
@commodityName varchar(100),
@inPrice money,
@outPrice money,
@amount int--@commodityId int output
as
declare @sortid int
select @sortid=SortId from CommoditySort where SortName=@sortName
--根据输入的名称查看类别编号是否存在
if @sortid is null
begin
return -1 --用-1代表类别名不正确
end
--向商品信息表添加一条商品信息
insert into CommodityInfo(SortId,CommodityName,InPrice,OutPrice,Amount)
values(@sortid,@commodityName,@inPrice,@outPrice,@amount)
if @@ERROR >0
begin
return 0 --用0来代表插入信息失败
end
else
begin
return @@IDENTITY
end
go
--来使用带返回的存储过程,返回值有三个,0,-1 ,商品的编号
--使用显示调用
declare @Result int -- 接受存储过程的返回值
exec @Result=usp_insertCommodityReturn @sortName='会变美食',@commodityName='好吃点',
@inprice=3.5,@outprice=7.6 ,@amount=100
if @Result =-1
begin
print '对不起,输入的类别名称不存在'
end
else if @Result=0
begin
print '插入的信息失败'
end
else
begin
print'添加商品成功,商品编号为'+convert(varchar(5),@Result)
end
go
创建存储过程的注意事项:
1.有默认值的参数要写在最后
2.存储过程创建结束,必须加批处理的go 否则的话会造成递归调用
1.不写参数名,必须与定义的时候的参数顺序相同
2.不按照顺序,必须写上参数名
3.如果有一个写为“@名称=值”的形式,那么后面的所有参数都要这样写
4.如果调用存储过程的批处理中的第一句话,也就是go
exec 存储过程名称
这样的格式可以不写exec,也就是
go
存储过程名称