存储过程

一、存储过程简介
1.定义:存储过程(Stored Procedure)是一组为了完成特定功能的SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。

2.存储过程的分类:

1) 系统存储过程:sp_开头,用来进行系统的各项设定.取得信息.相关管理工作

2) 本地存储过程:用户创建的存储过程是由用户创建并完成某一特定功能的存储过程,事实上一般所说的存储过程就是指本地存储过程。

3) 临时存储过程:分为两种存储过程:一是本地临时存储过程,以井字号(#)作为其名称的第一个字符,则该存储过程将成为一个存放在tempdb数据库中的本地临时存储过程,且只有创建它的用户才能执行它;二是全局临时存储过程,以两个井字号(##)号开始,则该存储过程将成为一个存储在tempdb数据库中的全局临时存储过程,全局临时存储过程一旦创建,以后连接到服务器的任意用户都可以执行它,而且不需要特定的权限。

4) 远程存储过程:在SQL Server2005中,远程存储过程(Remote Stored Procedures)是位于远程服务器上的存储过程,通常可以使用分布式查询和EXECUTE命令执行一个远程存储过程。

5) 扩展存储过程:扩展存储过程(Extended Stored Procedures)是用户可以使用外部程序语言编写的存储过程,而且扩展存储过程的名称通常以xp_开头。

3.存储过程的优点:

1) 存储过程的能力大大增强了SQL语言的功能和灵活性。存储过程可以用流控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的 运算。

2) 可保证数据的安全性和完整性通过存储过程可以使没有权限的用户在控制之下间接地存取数据库,从而保证数据的安全;通过存储过程可以使相关的动作在一起发生,从而可以维护数据库的完整性。

3) 在运行存储过程前,数据库已对其进行了语法和句法分析,并给出了优化执行方案。这种已经编译好的过程可极大地改善SQL语句的性能。由于执行SQL语句的大部分工作已经完成,所以存储过程能以极快的速度执行。

4) 可以降低网络的通信量。

5) 使体现企业规则的运算程序放入数据库服务器中,以便:

集中控制;

当企业规则发生变化时在服务器中改变存储过程即可,无须修改任何应用程序。企业规则的特点是要经常变化,如果把体现企业规则的运算程序放入应用程序中,则当企业规则发生变化时,就需要修改应用程序工作量非常之大(修改、发行和安装应用程序)。如果把体现企业规则的运算放入存储过程中,则当企业规则发生变化时,只要修改存储过程就可以了,应用程序无须任何变化。



二、SQLserver的存储语法

创建存储过程,存储过程是保存起来的可以接受和返回用户提供的参数的 Transact-SQL 语句的集合。

  可以创建一个过程供永久使用,或在一个会话中临时使用(局部临时过程),或在所有会话中临时使用(全局临时过程)。

  也可以创建在 Microsoft? SQLServer? 启动时自动运行的存储过程。

  语法

  CREATE PROC [ EDURE ]procedure_name [ ; number ]

    [ { @parameterdata_type }

      [ VARYING ] [ =default ] [ OUTPUT ]

    ] [ ,...n ]

  [ WITH

    { RECOMPILE |ENCRYPTION | RECOMPILE , ENCRYPTION } ]

  [ FOR REPLICATION ]

  AS sql_statement [...n ]

 执行: EXEC  procedure_name

参数

  procedure_name
  新存储过程的名称。过程名必须符合标识符规则,且对于数据库及其所有者必须唯一。
  要创建局部临时过程,可以在procedure_name 前面加一个编号符(#procedure_name),要创建全局临时过程,可以在procedure_name 前面加两个编号符(##procedure_name)。完整的名称(包括 # 或 ##)不能超过 128 个字符。指定过程所有者的名称是可选的。

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

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

  data_type
  参数的数据类型。所有数据类型(包括 text、ntext 和 image)均可以用作存储过程的参数。不过,cursor 数据类型只能用于 OUTPUT 参数。如果指定的数据类型为 cursor,也必须同时指定 VARYING和 OUTPUT 关键字。
  说明 对于可以是 cursor 数据类型的输出参数,没有最大数目的限制。

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

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

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

  n
  表示最多可以指定 2.100 个参数的占位符。
  {RECOMPILE |ENCRYPTION | RECOMPILE, ENCRYPTION}
  RECOMPILE 表明 SQL Server 不会缓存该过程的计划,该过程将在运行时重新编译。在使用非典型值或临时值而不希望覆盖缓存在内存中的执行计划时,请使用 RECOMPILE 选项。
  ENCRYPTION 表示 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE 语句文本的条目。使用ENCRYPTION 可防止将过程作为 SQL Server 复制的一部分发布。
  说明 在升级过程中,SQL Server 利用存储在 syscomments 中的加密注释来重新创建加密过程。

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

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

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

  n
  是表示此过程可以包含多条Transact-SQL 语句的占位符。

  注释
  存储过程的最大大小为 128 MB。


三、Oracle的存储过程

存储过程创建语法:

       create or replace procedure 存储过程名(param1 in type,param2 out type)

as | is

变量1 类型(值范围);

变量2 类型(值范围);

Begin

    Select count(*) into 变量1 from 表A where列名=param1;

    If (判断条件) then

       Select 列名 into 变量2 from 表A where列名=param1;

       Dbms_output。Put_line(‘打印信息’);

    Elsif (判断条件) then

       Dbms_output。Put_line(‘打印信息’);

    Else

       Raise 异常名(NO_DATA_FOUND);

    End if;

Exception

    When others then

       Rollback;

End;

 

注意事项:

1,  存储过程参数不带取值范围,in表示传入,out表示输出

2,  变量带取值范围,后面接分号

3,  在判断语句前最好先用count(*)函数判断是否存在该条操作记录

4,  用select 。。。into。。。给变量赋值

5,  在代码中抛异常用 raise+异常名

 

 

以命名的异常

命名的系统异常                          产生原因

ACCESS_INTO_NULL                   未定义对象

CASE_NOT_FOUND                     CASE 中若未包含相应的 WHEN ,并且没有设置

ELSE 时

COLLECTION_IS_NULL                集合元素未初始化

CURSER_ALREADY_OPEN          游标已经打开

DUP_VAL_ON_INDEX                   唯一索引对应的列上有重复的值

INVALID_CURSOR                 在不合法的游标上进行操作

INVALID_NUMBER                       内嵌的 SQL 语句不能将字符转换为数字

NO_DATA_FOUND                        使用 select into 未返回行,或应用索引表未初始化的 

 

TOO_MANY_ROWS                      执行 select into 时,结果集超过一行

ZERO_DIVIDE                              除数为 0

SUBSCRIPT_BEYOND_COUNT     元素下标超过嵌套表或 VARRAY 的最大值

SUBSCRIPT_OUTSIDE_LIMIT       使用嵌套表或 VARRAY 时,将下标指定为负数

VALUE_ERROR                             赋值时,变量长度不足以容纳实际数据

LOGIN_DENIED                           PL/SQL 应用程序连接到 oracle 数据库时,提供了不

正确的用户名或密码

NOT_LOGGED_ON                       PL/SQL 应用程序在没有连接 oralce 数据库的情况下

访问数据

PROGRAM_ERROR                       PL/SQL 内部问题,可能需要重装数据字典& pl./SQL

系统包

ROWTYPE_MISMATCH                宿主游标变量与 PL/SQL 游标变量的返回类型不兼容

SELF_IS_NULL                             使用对象类型时,在 null 对象上调用对象方法

STORAGE_ERROR                        运行 PL/SQL 时,超出内存空间

SYS_INVALID_ID                         无效的 ROWID 字符串

TIMEOUT_ON_RESOURCE         Oracle 在等待资源时超时

1.基本结构
CREATE OR REPLACE PROCEDURE 存储过程名字(参数1 IN NUMBER, 参数2 IN NUMBER) 
 IS
  变量1 INTEGER :=0;
  变量2 DATE;BEGIN
 END 存储过程名字

2.SELECT INTO STATEMENT
将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
例子:
BEGIN
 SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
 EXCEPTIONWHEN NO_DATA_FOUND
  THEN xxxx;
 END;
 
3.IF 判断
 IF V_TEST=1 THEN
  BEGIN
   do something
  END;
 END IF;

4.while 循环
 WHILE V_TEST=1 LOOP
  BEGINXXXXEND;
 END LOOP;

5.变量赋值
 V_TEST := 123;
 
6.用for in 使用cursor
 ...
 IS
 CURSOR cur IS SELECT * FROM xxx;
 BEGIN
  FOR cur_result in cur LOOP
  BEGIN
   V_SUM :=cur_result.列名1+cur_result.列名2
  END;
  END LOOP;
 END;
 
 
7.带参数的cursor
CURSOR C_USER(C_ID NUMBER)
 IS
 SELECT NAME FROM USER WHERE TYPEID=C_ID;
  OPEN C_USER(变量值);
   LOOP
    FETCH C_USER INTO V_NAME;
    EXIT FETCH C_USER%NOTFOUND;
    do something
   END LOOP;
  CLOSE C_USER;


四、举例

 A. 使用带有复杂 SELECT 语句的简单过程

  下面的存储过程从四个表的联接中返回所有作者(提供了姓名)、出版的书籍以及出版社。该存储过程不使用任何参数。

  USE pubs

  IF EXISTS (SELECT nameFROM sysobjects

       WHERE name =\'au_info_all\' AND type = \'P\')

    DROP PROCEDUREau_info_all

  GO

  CREATE PROCEDUREau_info_all

  AS

  SELECT au_lname, au_fname,title, pub_name

    FROM authors a INNERJOIN titleauthor ta

     ON a.au_id =ta.au_id INNER JOIN titles t

     ON t.title_id =ta.title_id INNER JOIN publishers p

     ON t.pub_id =p.pub_id

  GO

  au_info_all 存储过程可以通过以下方法执行:

  EXECUTE au_info_all

  -- Or

  EXEC au_info_all

  如果该过程是批处理中的第一条语句,则可使用:

  au_info_all

 

B. 使用带有参数的简单过程

  下面的存储过程从四个表的联接中只返回指定的作者(提供了姓名)、出版的书籍以及出版社。该存储过程接受与传递的参数精确匹配的值。

  USE pubs

  IF EXISTS (SELECT nameFROM sysobjects

       WHERE name = \'au_info\'AND type = \'P\')

    DROP PROCEDUREau_info

  GO

  USE pubs

  GO

  CREATE PROCEDUREau_info

    @lastnamevarchar(40),

    @firstnamevarchar(20)

  AS

  SELECT au_lname,au_fname, title, pub_name

    FROM authors a INNERJOIN titleauthor ta

     ON a.au_id =ta.au_id INNER JOIN titles t

     ON t.title_id =ta.title_id INNER JOIN publishers p

     ON t.pub_id =p.pub_id

    WHERE au_fname = @firstname

     AND au_lname =@lastname

  GO

  au_info 存储过程可以通过以下方法执行:

  EXECUTE au_info\'Dull\', \'Ann\'

  -- Or

  EXECUTE au_info@lastname = \'Dull\', @firstname = \'Ann\'

  -- Or

  EXECUTE au_info@firstname = \'Ann\', @lastname = \'Dull\'

  -- Or

  EXEC au_info \'Dull\',\'Ann\'

  -- Or

  EXEC au_info @lastname= \'Dull\', @firstname = \'Ann\'

  -- Or

  EXEC au_info@firstname = \'Ann\', @lastname = \'Dull\'

  如果该过程是批处理中的第一条语句,则可使用:

  au_info \'Dull\',\'Ann\'

  -- Or

  au_info @lastname =\'Dull\', @firstname = \'Ann\'

  -- Or

  au_info @firstname =\'Ann\', @lastname = \'Dull\'

 

C. 使用带有通配符参数的简单过程

  下面的存储过程从四个表的联接中只返回指定的作者(提供了姓名)、出版的书籍以及出版社。该存储过程对传递的参数进行模式匹配,如果没有提供参数,则使用预设的默认值。

  USE pubs

  IF EXISTS (SELECT nameFROM sysobjects

     WHERE name =\'au_info2\' AND type = \'P\')

    DROP PROCEDUREau_info2

  GO

  USE pubs

  GO

  CREATE PROCEDUREau_info2

    @lastnamevarchar(30) = \'D%\',

    @firstnamevarchar(18) = \'%\'

  AS

  SELECT au_lname,au_fname, title, pub_name

  FROM authors a INNERJOIN titleauthor ta

    ON a.au_id =ta.au_id INNER JOIN titles t

    ON t.title_id =ta.title_id INNER JOIN publishers p

    ON t.pub_id =p.pub_id

  WHERE au_fname LIKE@firstname

    AND au_lname LIKE@lastname

  GO

  au_info2 存储过程可以用多种组合执行。下面只列出了部分组合:

  EXECUTE au_info2

  -- Or

  EXECUTE au_info2\'Wh%\'

  -- Or

  EXECUTE au_info2@firstname = \'A%\'

  -- Or

  EXECUTE au_info2\'[CK]ars[OE]n\'

  -- Or

  EXECUTE au_info2\'Hunter\', \'Sheryl\'

  -- Or

  EXECUTE au_info2\'H%\', \'S%\'

--------------------------------------------------------------------------------

 

 

 

 

D. 使用 OUTPUT 参数

  OUTPUT 参数允许外部过程、批处理或多条 Transact-SQL 语句访问在过程执行期间设置的某个值。下面的示例创建一个存储过程 (titles_sum),并使用一个可选的输入参数和一个输出参数。

  首先,创建过程:

  USE pubs

  GO

  IF EXISTS(SELECT nameFROM sysobjects

     WHERE name =\'titles_sum\' AND type = \'P\')

    DROP PROCEDUREtitles_sum

  GO

  USE pubs

  GO

  CREATE PROCEDUREtitles_sum @@TITLE varchar(40) = \'%\', @@SUM money OUTPUT

  AS

  SELECT \'Title Name\'= title

  FROM titles

  WHERE title LIKE@@TITLE

  SELECT @@SUM =SUM(price)

  FROM titles

  WHERE title LIKE@@TITLE

  GO

  接下来,将该 OUTPUT 参数用于控制流语言。

  说明 OUTPUT 变量必须在创建表和使用该变量时都进行定义。

  参数名和变量名不一定要匹配,不过数据类型和参数位置必须匹配(除非使用 @@SUM = variable 形式)。

  DECLARE @@TOTALCOSTmoney

  EXECUTE titles_sum\'The%\', @@TOTALCOST OUTPUT

  IF @@TOTALCOST <200

  BEGIN

    PRINT \' \'

    PRINT \'All of thesetitles can be purchased for less than $200.\'

  END

  ELSE

    SELECT \'The totalcost of these titles is $\'

       +RTRIM(CAST(@@TOTALCOST AS varchar(20)))

  下面是结果集:

  Title Name                               

  ------------------------------------------------------------------------

  The Busy Executive\'sDatabase Guide

  The Gourmet Microwave

  The Psychology ofComputer Cooking

  (3 row(s) affected)

  Warning, null valueeliminated from aggregate.

  All of these titlescan be purchased for less than $200.

 

 

E. 使用 OUTPUT 游标参数

  OUTPUT 游标参数用来将存储过程的局部游标传递回调用批处理、存储过程或触发器。

  首先,创建以下过程,在 titles 表上声明并打开一个游标:

  USE pubs

  IF EXISTS (SELECT nameFROM sysobjects

     WHERE name =\'titles_cursor\' and type = \'P\')

  DROP PROCEDUREtitles_cursor

  GO

  CREATE PROCEDUREtitles_cursor @titles_cursor CURSOR VARYING OUTPUT

  AS

  SET @titles_cursor =CURSOR

  FORWARD_ONLY STATICFOR

  SELECT *

  FROM titles

  OPEN @titles_cursor

  GO

  接下来,执行一个批处理,声明一个局部游标变量,执行上述过程以将游标赋值给局部变量,然后从该游标提取行。

  USE pubs

  GO

  DECLARE @MyCursorCURSOR

  EXEC titles_cursor@titles_cursor = @MyCursor OUTPUT

  WHILE (@@FETCH_STATUS= 0)

  BEGIN

    FETCH NEXT FROM@MyCursor

  END

  CLOSE @MyCursor

  DEALLOCATE @MyCursor

  GO

 

 F. 使用 WITH RECOMPILE 选项

  如果为过程提供的参数不是典型的参数,并且新的执行计划不应高速缓存或存储在内存中,WITH RECOMPILE 子句会很有帮助。

  USE pubs

  IF EXISTS (SELECT nameFROM sysobjects

     WHERE name =\'titles_by_author\' AND type = \'P\')

    DROP PROCEDUREtitles_by_author

  GO

  CREATE PROCEDUREtitles_by_author @@LNAME_PATTERN varchar(30) = \'%\'

  WITH RECOMPILE

  AS

  SELECT RTRIM(au_fname)+ \' \' + RTRIM(au_lname) AS \'Authors full name\',

    title AS Title

  FROM authors a INNERJOIN titleauthor ta

    ON a.au_id =ta.au_id INNER JOIN titles t

    ON ta.title_id =t.title_id

  WHERE au_lname LIKE@@LNAME_PATTERN

  GO

 

 

 

G. 使用 WITH ENCRYPTION 选项

  WITH ENCRYPTION 子句对用户隐藏存储过程的文本。下例创建加密过程,使用 sp_helptext 系统存储过程获取关于加密过程的信息,然后尝试直接从 syscomments 表中获取关于该过程的信息。

  IF EXISTS (SELECT nameFROM sysobjects

     WHERE name =\'encrypt_this\' AND type = \'P\')

    DROP PROCEDUREencrypt_this

  GO

  USE pubs

  GO

  CREATE PROCEDUREencrypt_this

  WITH ENCRYPTION

  AS

  SELECT *

  FROM authors

  GO

  EXEC sp_helptextencrypt_this

  下面是结果集:

  The object\'s commentshave been encrypted.

  接下来,选择加密存储过程内容的标识号和文本。

  SELECT c.id, c.text

  FROM syscomments cINNER JOIN sysobjects o

    ON c.id = o.id

  WHERE o.name = \'encrypt_this\'

  下面是结果集:

  说明 text 列的输出显示在单独一行中。执行时,该信息将与 id 列信息出现在同一行中。

  id     text                            

  ----------------------------------------------------------------------

  1413580074

  (1 row(s) affected)

H. 创建用户定义的系统存储过程

  下面的示例创建一个过程,显示表名以 emp 开头的所有表及其对应的索引。如果没有指定参数,该过程将返回表名以 sys 开头的所有表(及索引)。

  IF EXISTS (SELECT nameFROM sysobjects

     WHERE name =\'sp_showindexes\' AND type = \'P\')

    DROP PROCEDUREsp_showindexes

  GO

  USE master

  GO

  CREATE PROCEDUREsp_showindexes

    @@TABLE varchar(30)= \'sys%\'

  AS

  SELECT o.name ASTABLE_NAME,

    i.name ASINDEX_NAME,

    indid AS INDEX_ID

  FROM sysindexes iINNER JOIN sysobjects o

    ON o.id = i.id

  WHERE o.name LIKE@@TABLE

  GO    

  USE pubs

  EXEC sp_showindexes\'emp%\'

  GO

  下面是结果集:

  TABLE_NAME    INDEX_NAME    INDEX_ID

  -------------------------------- ----------------

  employee     employee_ind   1

  employee     PK_emp_id    2

  (2 row(s) affected)

 

I. 使用延迟名称解析

  下面的示例显示四个过程以及延迟名称解析的各种可能使用方式。尽管引用的表或列在编译时不存在,但每个存储过程都可创建。

  IF EXISTS (SELECT nameFROM sysobjects

     WHERE name =\'proc1\' AND type = \'P\')

    DROP PROCEDURE proc1

  GO

  -- Creating aprocedure on a nonexistent table.

  USE pubs

  GO

  CREATE PROCEDURE proc1

  AS

    SELECT *

    FROM does_not_exist

  GO 

  -- Here is thestatement to actually see the text of the procedure.

  SELECT o.id, c.text

  FROM sysobjects oINNER JOIN syscomments c

    ON o.id = c.id

  WHERE o.type = \'P\'AND o.name = \'proc1\'

  GO

  USE master

  GO

  IF EXISTS (SELECT nameFROM sysobjects

     WHERE name =\'proc2\' AND type = \'P\')

    DROP PROCEDURE proc2

  GO

  -- Creating aprocedure that attempts to retrieve information from a

  -- nonexistent columnin an existing table.

  USE pubs

  GO

  CREATE PROCEDURE proc2

  AS

    DECLARE @middle_initchar(1)

    SET @middle_init =NULL

    SELECT au_id,middle_initial = @middle_init

    FROM authors

  GO 

  -- Here is thestatement to actually see the text of the procedure.

  SELECT o.id, c.text

  FROM sysobjects oINNER JOIN syscomments c

    ON o.id = c.id

  WHERE o.type = \'P\'and o.name = \'proc2\'



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值