数据库存储过程讲解与实例

目录

1 存储过程简介

2 存储过程使用

2.1 创建存储过程

2.2 in,out以及inout


1 存储过程简介

 SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。

    存储过程是可编程的函数,在数据库中创建并保存,可以由SQL语句和控制结构组成。当想要在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟,它允许控制数据的访问方式。

优点

  • 存储过程可封装,并隐藏复杂的商业逻辑。
  • 存储过程可以回传值,并可以接受参数。
  • 存储过程无法使用 SELECT 指令来运行,因为它是子程序,与查看表,数据表或用户定义函数不同。
  • 存储过程可以用在数据检验,强制实行商业逻辑等。

缺点

  • 存储过程,往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。
  • 存储过程的性能调校与撰写,受限于各种数据库系统。

2 存储过程使用

存储过程的一些基本语法:

--------------创建存储过程-----------------

CREATE PROC [ EDURE ] procedure_name [ ; number ]
    [ { @parameter data_type }
        [ VARYING ] [ = default ] [ OUTPUT ]
    ] [ ,...n ]

[ WITH
    { RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ]

[ FOR REPLICATION ]

AS sql_statement [ ...n ]

--------------调用存储过程-----------------

EXECUTE Procedure_name '' --存储过程如果有参数,后面加参数格式为:@参数名=value,也可直接为参数值value

--------------删除存储过程-----------------

drop procedure procedure_name    --在存储过程中能调用另外一个存储过程,而不能删除另外一个存储过程

创建存储过程的参数:
1.procedure_name :存储过程的名称,在前面加#为局部临时存储过程,加##为全局临时存储过程。

2.; number:是可选的整数,用来对同名的过程分组,以便用一条 DROP PROCEDURE 语句即可将同组的过程一起除去。例如,名为 orders 的应用程序使用的过程可以命名为 orderproc;1、orderproc;2 等。DROP PROCEDURE orderproc 语句将除去整个组。如果名称中包含定界标识符,则数字不应包含在标识符中,只应在 procedure_name 前后使用适当的定界符。 

3.@parameter: 存储过程的参数。可以有一个或多个。用户必须在执行过程时提供每个所声明参数的值(除非定义了该参数的默认值)。存储过程最多可以有 2.100 个参数。 
使用 @ 符号作为第一个字符来指定参数名称。参数名称必须符合标识符的规则。每个过程的参数仅用于该过程本身;相同的参数名称可以用在其它过程中。默认情况下,参数只能代替常量,而不能用于代替表名、列名或其它数据库对象的名称。有关更多信息,请参见 EXECUTE。 

4.data_type:参数的数据类型。所有数据类型(包括 text、ntext 和 image)均可以用作存储过程的参数。不过,cursor 数据类型只能用于 OUTPUT 参数。如果指定的数据类型为 cursor,也必须同时指定 VARYING 和 OUTPUT 关键字。有关 SQL Server 提供的数据类型及其语法的更多信息,请参见数据类型。 
说明 对于可以是 cursor 数据类型的输出参数,没有最大数目的限制。 

5.VARYING: 指定作为输出参数支持的结果集(由存储过程动态构造,内容可以变化)。仅适用于游标参数。 

6.default: 参数的默认值。如果定义了默认值,不必指定该参数的值即可执行过程。默认值必须是常量或 NULL。如果过程将对该参数使用 LIKE 关键字,那么默认值中可以包含通配符(%、_、[] 和 [^])。

7.OUTPUT :表明参数是返回参数。该选项的值可以返回给 EXEC[UTE]。使用 OUTPUT 参数可将信息返回给调用过程。Text、ntext 和 image 参数可用作 OUTPUT 参数。使用 OUTPUT 关键字的输出参数可以是游标占位符。 

8.RECOMPILE: 表明 SQL Server 不会缓存该过程的计划,该过程将在运行时重新编译。在使用非典型值或临时值而不希望覆盖缓存在内存中的执行计划时,请使用 RECOMPILE 选项。

9.ENCRYPTION: 表示 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE 语句文本的条目。使用 ENCRYPTION 可防止将过程作为 SQL Server 复制的一部分发布。 说明 在升级过程中,SQL Server 利用存储在 syscomments 中的加密注释来重新创建加密过程。 

10.FOR REPLICATION :指定不能在订阅服务器上执行为复制创建的存储过程。.使用 FOR REPLICATION 选项创建的存储过程可用作存储过程筛选,且只能在复制过程中执行。本选项不能和 WITH RECOMPILE 选项一起使用。 

11.AS :指定过程要执行的操作。

12.sql_statement :过程中要包含的任意数目和类型的 Transact-SQL 语句。但有一些限制。

2.1 创建存储过程

UserAccount
UserIDUserNamePassWordRegisterTimeRegisterIP
126                   6                   2012-12-316
185                   5                   2013-01-015
191                   1                   2013-01-011
202                   2                   2013-01-012
213                   3                   2013-01-013
224                   4                   2013-01-014
235                   5                   2013-01-015
257                   7                   2013-01-017
268                   8                   2013-01-018
NULLNULLNULLNULLNULL

针对上面的表,我使用存储过程对它做一些操作:

1. 只返回单一记录集的存储过程 

-------------创建名为GetUserAccount的存储过程----------------
create Procedure GetUserAccount
as
select * from UserAccount
go

-------------执行上面的存储过程----------------
exec GetUserAccount

 结果:相当于运行 select * from UserAccount 这行代码,结果为整个表的数据。

2.没有输入输出的存储过程 

-------------创建名为GetUserAccount的存储过程----------------

create Procedure inUserAccount
as
insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(9,9,'2013-01-02',9)
go

-------------执行上面的存储过程----------------

exec inUserAccount

结果:相当于运行 insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(9,9,'2013-01-02',9) 这行代码。

3.有返回值的存储过程 

-------------创建名为GetUserAccount的存储过程----------------

create Procedure inUserAccountRe
as
insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(10,10,'2013-01-02',10)
return @@rowcount
go

-------------执行上面的存储过程----------------

exec inUserAccountRe

 解释:这里的@@rowcount为执行存储过程影响的行数,执行的结果是不仅插入了一条数据,还返回了一个值即 return value =1  ,这个可以在程序中获取,稍后在c#调用存储过程中会有说到。

4.有输入参数和输出参数的存储过程 

-------------创建名为GetUserAccount的存储过程----------------

create Procedure GetUserAccountRe
@UserName nchar(20),
@UserID int output
as
if(@UserName>5)
select @UserID=COUNT(*) from UserAccount where UserID>25
else
set @UserID=1000
go

-------------执行上面的存储过程----------------

exec GetUserAccountRe '7',null

解释:@UserName为输入参数,@UserID为输出参数。 运行结果为@userID为COOUT(*)即 =1。

5. 同时具有返回值、输入参数、输出参数的存储过程 

-------------创建名为GetUserAccount的存储过程----------------

create Procedure GetUserAccountRe1
@UserName nchar(20),
@UserID int output
as
if(@UserName>5)
select @UserID=COUNT(*) from UserAccount where UserID>25
else
set @UserID=1000
return @@rowcount
go

-------------执行上面的存储过程----------------

exec GetUserAccountRe1 '7',null

结果:@userID为COOUT(*)即 =1,Retun Value=1。

6.同时返回参数和记录集的存储过程 

-------------创建名为GetUserAccount的存储过程----------------

create Procedure GetUserAccountRe2
@UserName nchar(20),
@UserID int output
as
if(@UserName>5)
select @UserID=COUNT(*) from UserAccount where UserID>25
else
set @UserID=1000
select * from UserAccount
return @@rowcount
go

-------------执行上面的存储过程----------------

exec GetUserAccountRe2 '7',null

结果:返回执行 select * from UserAccount 这句代码的结果集,同时@userID为COOUT(*)即 =1,Retun Value=9。 

7.返回多个记录集的存储过程 

-------------创建名为GetUserAccount的存储过程----------------

create Procedure GetUserAccountRe3
as
select * from UserAccount
select * from UserAccount where UserID>5
go

-------------执行上面的存储过程----------------

exec GetUserAccountRe3

结果:返回两个结果集,一个为 select * from UserAccount,另一个为 select * from UserAccount where UserID>5 。

2.2 in,out以及inout

  MySQL存储过程的参数用在存储过程的定义,共有三种参数类型

    IN,OUT,INOUT
    格式为:Create procedure|function([[IN |OUT |INOUT ] 参数名 数据类形...])

    IN 输入参数
        表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值

    OUT 输出参数
        该值可在存储过程内部被改变,并可返回

    INOUT 输入输出参数
        调用时指定,并且可被改变和返回

1.参数in的使用(代表输入,意思说你的参数要传到存过过程的过程里面去)

//为了避免存储过程中分号(";")结束语句,我们使用分隔符告诉mysql解释器,该段命令是否已经结束了。

/**
案例功能:求1-n的和
*/

delimiter $
create procedure p1(in n int)
begin
declare total int default 0;
declare num int default 0;
while num < n do
set num:=num+1;
set total:=total+num;
end while;
select total;
end$

call p1(10)$

创建并执行完存储过程,运行结果如下:

2.参数out的使用(代表往外输出)

//这里还要注意一点的就是我们的输出参数一定要设置相应类型的初始,否则不管你怎么计算得出的结果都为NULL值

/**
案例功能:求1-n的和
*/

create procedure p2(in n int,out total int)
begin
declare num int default 0;
set total:=0;
while num < n do
set num:=num+1;
set total:=total+num;
end while;
end$

注意:对于第一个输入参数我们可以理解,但是第二个输出参数我们到底应该怎么输?

这里我们需要对第二个参数定义一个变量名(更形象点就是你输入一个输入类型的参数n,由输出参数total往外发射输出我们只需要定义一个变量名来接收这个输出值即可)

call p2(100,@sum)$//这里的@sum就是我定义用来接收处处total的值

select @sum$

创建并执行完存储过程(查询定义的变量值),运行结果如下:

总结in、out区别:

in:表示输入一个值,你需要一个值,我给你一个值

out:你往外输出一个值,你输出的那个值我就拿一个变量来接收你给我输出的那个值

3.参数inout的使用(既能输入一个值又能传出来一个值)

/**
功能:传一个年龄,自动让年龄增长10岁
*/
create procedure p3(inout age int)
begin
set age:=age+10;
end$

注意:调用的时候,我这里需要和大家声明一下,inout型的参数值既是输入类型又是输出类型,你给它一个值,值不是变量,不是变量那out的时候它怎么赋给这个值是不是?

因此我们需要先设置一个变量并初始化这个值,调用的时候直接传这个变量即可。

set @currentAge=8$

call p3(@currentAge)$

select @currentAge$

创建并执行完存储过程,运行结果如下:

使用参数的存储过程(备注:decimal(8,2)意思就是总共有8位,小数点后留两位)

create procedure procedureName( 
    out min decimal(8,2), 
    out avg decimal(8,2), 
    out max decimal(8,2) 
) 
BEGIN 
    select MIN(price) INTO min from order; 
    select AVG(price) into avg from order; 
    select MAX(price) into max from order; 
END;  

此过程接受三个参数, 分别用于获取订单表的最小、平均、最大价格。每个参数必须具有指定的类

型,这里使用十进制值(decimal(8,2)), 关键字OUT指出相应的参数用来从存储过程传出

一个值(返回给调用者)

MySQL支持IN(传递给存储过程)、OUT(从存储过程传出,如这里所用)和INOUT(对存储过程传入和传出)类型的参数。存储过程的代码位于BEGIN和END语句内,如前所见,它们是一系列SELECT语句,用来检索值,然后保存到相应的变量(通过指定INTO关键字)

为调用此修改过的存储过程,必须指定3个变量名,如下所示:(所有MySQL变量都必须以@开始。)

 

-- 由于过程指定三个参数, 故调用必须要参数匹配 
call procedureName(@min, @avg, @max);  

该调用并没有任何输出, 只是把调用的结果赋给了调用时传入的变量(@min, @avg, @max)。然后即可调用显示该变量的值。

select @min, @avg, @max; 

结果如下

@min@avg@max
42.00601.002222.00

使用in参数, 输入一个用户id, 返回该用户所有订单的总价格。

create procedure getTotalById ( 
    in userId int, 
    out total decimal(8,2) 
) 
BEGIN 
    select SUM(r.price) from order r 
    where r.u_id = userId 
    into total; 
END;  

调用存储过程

 

call getTotalById(1, @total); 

select @total;  

结果将返回该用户所有订单的合计价格。

复杂一点的过程, 根据用户id获取该用户的所有订单价格, 并动态的选择是否加税。代码设计如下

 

create procedure getTotalByUser2( 
    in userId int, 
    in flag boolean, -- 是否加税标记 
    out total decimal(8,2) 
) 
begin 
    DECLARE tmptotal DECIMAL(8,2); 
    DECLARE taxrate int DEFAULT 6;-- 默认的加税的利率 
     
    select SUM(r.price) from order r 
    where r.u_id = userId 
    into tmptotal; 
     
    if flag then 
        select tmptotal + (tmptotal/1000*taxrate) into tmptotal; 
    end if; 
     
    select tmptotal into total; 
END;  

该过程传入三个参数, 用户id, 是否加税以及返回的总价格,在过程内部, 定义两个局部变量tmptotal和taxrate,把查询出来的结果赋给临时变量, 在判断是否加税。最后把局部变量的值赋给输出参数。

 

call getTotalByUser2(1, false, @total); -- 不加税 
call getTotalByUser2(1, true, @total);  -- 加税 
select @total; 

 

 

  • 20
    点赞
  • 127
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Visual C++与SQL Server数据库应用系统开发与实例课本内容是一本介绍如何使用Visual C++开发与SQL Server数据库结合的应用系统的教材。该书包含了以下内容: 1. Visual C++和SQL Server的基础知识:介绍了Visual C++和SQL Server的基本概念、环境设置和操作方法,帮助读者建立起开发环境。 2. SQL Server数据库的设计与管理:讲解了如何使用SQL Server进行数据库设计,包括表的创建与管理、数据类型的选择、索引和约束的应用,并介绍了常用的SQL语句和存储过程。 3. Visual C++的开发基础:介绍了Visual C++的开发环境和基本的语法,包括变量、条件语句、循环结构、函数和类的定义等内容。 4. Visual C++与SQL Server的连接与操作:详细讲解了如何使用Visual C++代码与SQL Server进行连接,并进行数据的插入、更新、查询和删除操作。还介绍了使用ADO.NET和ODBC等数据访问技术与SQL Server进行交互的方法。 5. 实例开发与案例分析:通过实际的案例,展示了如何将Visual C++和SQL Server结合应用于实际项目开发中。涵盖了不同领域的应用系统,如学生信息管理系统、图书馆管理系统、进销存系统等,帮助读者理解并应用所学知识。 通过学习该课本,读者可以掌握使用Visual C++进行应用系统开发,并与SQL Server数据库进行集成的方法和技巧。同时,通过实例讲解与案例的分析,读者还可以了解到如何将所学知识应用于实际项目开发中,提高开发效率和质量。这对于计算机科学、软件工程等相关专业的学生和从事应用系统开发的从业人员来说,是一本实用而重要的教材。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值