存储过程原理与案例

存储过程原理与案例,第1张

概述目录 1.sql存储过程概述 2.SQL存储过程创建 3.sql存储过程定义语句 4.存储过程案例应用   1. sql存储过程概述 在大型数据库系统中,存储过程和触发器具有很重要的作用。无论是存储过程还是触发器,都是SQL 语句和流程控制语句的集合。就本质而言,触发器也是一种存储过程。存储过 程在运算时生成执行方式,所以,以后对其再运行时其执行速度很快。SQL Server 2000 不仅提供了


目录

1.sql存储过程概述
2.sql存储过程创建
3.sql存储过程定义语句
4.存储过程案例应用
 

1. sql存储过程概述


在大型数据库系统中,存储过程和触发器具有很重要的作用。无论是存储过程还是触发器,都是sql 语句和流程控制语句的集合。就本质而言,触发器也是一种存储过程。存储过

程在运算时生成执行方式,所以,以后对其再运行时其执行速度很快。sql Server 2000 不仅提供了用户自定义存储过程的功能,而且也提供了许多可作为工具使用的系统存储过

程。

    存储过程的概念

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

    在sql Server 的系列版本中存储过程分为两类:系统提供的存储过程和用户自定义存储过程。系统过程主要存储在master 数据库中并以sp_为前缀,并且系统存储过程主要是从系统表中获取信息,从而为系统管理员管理sql Server 提供支持。通过系统存储过程,MS sql Server 中的许多管理性或信息性的活动(如了解数据库对象、数据库信息)都可以被顺利有效地完成。尽管这些系统存储过程被放在master 数据库中,但是仍可以在其它数据库中对其进行调用,在调用时不必在存储过程名前加上数据库名。而且当创建一个新数据库时,一些系统存储过程会在新数据库中被自动创建。用户自定义存储过程是由用户创建并能完成某一特定功能(如查询用户所需数据信息)的存储过程。在本章中所涉及到的存储过程主要是指用户自定义存储过程。

    存储过程的优点

    当利用MS sql Server 创建一个应用程序时,Transaction-sql 是一种主要的编程语言。若运用Transaction-sql 来进行编程,有两种方法。其一是,在本地存储

Transaction- sql 程序,并创建应用程序向sql Server 发送命令来对结果进行处理。其二是,可以把部分用Transaction-sql 编写的程序作为存储过程存储在sql Server 中,并

创建应用程序来调用存储过程,对数据结果进行处理存储过程能够通过接收参数向调用者返回结果集,结果集的格式由调用者确定;返回状态值给调用者,指明调用是成功或是失

败;包括针对数据库的 *** 作语句,并且可以在一个存储过程中调用另一存储过程。

    我们通常更偏爱于使用第二种方法,即在sql Server 中使用存储过程而不是在客户计算机上调用Transaction-sql 编写的一段程序,原因在于存储过程具有以下优点:

    (1) 存储过程允许标准组件式编程

    存储过程在被创建以后可以在程序中被多次调用,而不必重新编写该存储过程的sql 语句。而且数据库专业人员可随时对存储过程进行修改,但对应用程序源代码毫无影响(

因为应用程序源代码只包含存储过程的调用语句),从而极大地提高了程序的可移植性。

    (2) 存储过程能够实现较快的执行速度

    如果某一 *** 作包含大量的Transaction-sql 代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的,在首次运行一个存储过程时,查

询优化器对其进行分析、优化,并给出最终被存在系统表中的执行计划。而批处理的Transaction- sql 语句在每次运行时都要进行编译和优化,因此速度相对要慢一些。

    (3) 存储过程能够减少网络流量

    对于同一个针对数据数据库对象的 *** 作(如查询、修改),如果这一 *** 作所涉及到的 Transaction-sql 语句被组织成一存储过程,那么当在客户计算机上调用该存储过程时,

网络中传送的只是该调用语句,否则将是多条sql 语句,从而大大增加了网络流量,降低网络负载。

    (4) 存储过程可被作为一种安全机制来充分利用

    系统管理员通过对执行某一存储过程的权限进行限制,从而能够实现对相应的数据访问权限的限制,避免非授权用户对数据的访问,保证数据的安全。

    注意:存储过程虽然既有参数又有返回值,但是它与函数不同。存储过程的返回值只是指明执行是否成功,并且它不能像函数那样被直接调用,也就是在调用存储过程时,在

存储过程名字前一定要有EXEC保留字。

2.sql存储过程创建


创建存储过程,存储过程是保存起来的可以接受和返回用户提供的参数的 Transact-sql 语句的集合。
  
  可以创建一个过程供永久使用,或在一个会话中临时使用(局部临时过程),或在所有会话中临时使用(全局临时过程)。
  
  也可以创建在 Microsoft sql Server  启动时自动运行的存储过程。
  
  语法
  CREATE PROC [ EDURE ] procedure_name [ ; number ]
    [ { @parameter data_type }
      [ varying ] [ = default ] [ OUTPUT ]
    ] [,...n ]
  
  [ WITH
    { RECOMPILE | ENCRYPTION | RECOMPILE,ENCRYPTION } ]
  
  [ FOR REPliCATION ]
  
  AS sql_statement [ ...n ]


参数
  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  
  过程中的参数。在 CREATE PROCEDURE 语句中可以声明一个或多个参数。用户必须在执行过程时提供每个所声明参数的值(除非定义了该参数的默认值)。存储过程最多可以

有 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。

用户定义的存储过程只能在当前数据库中创建(临时过程除外,临时过程总是在 tempdb 中创建)。在单个批处理中,CREATE PROCEDURE 语句不能与其它 Transact-sql 语句组合使用。
  
  默认情况下,参数可为空。如果传递 NulL 参数值并且该参数在 CREATE 或 ALTER table 语句中使用,而该语句中引用的列又不允许使用 NulL,则 sql Server 会产生一条

错误信息。为了防止向不允许使用 NulL 的列传递 NulL 参数值,应向过程中添加编程逻辑或为该列使用默认值(使用 CREATE 或 ALTER table 的 DEFAulT 关键字)。
  
  建议在存储过程的任何 CREATE table 或 ALTER table 语句中都为每列显式指定 NulL 或 NOT NulL,例如在创建临时表时。ANSI_DFLT_ON 和 ANSI_DFLT_OFF 选项控制 sql

Server 为列指派 NulL 或 NOT NulL 特性的方式(如果在 CREATE table 或 ALTER table 语句中没有指定的话)。如果某个连接执行的存储过程对这些选项的设置与创建该过程

的连接的设置不同,则为第二个连接创建的表列可能会有不同的为空性,并且表现出不同的行为方式。如果为每个列显式声明了 NulL 或 NOT NulL,那么将对所有执行该存储过程

的连接使用相同的为空性创建临时表。
  
  在创建或更改存储过程时,sql Server 将保存 SET QUOTED_IDENTIFIER 和 SET ANSI_NulLS 的设置。执行存储过程时,将使用这些原始设置。因此,所有客户端会话的 SET

QUOTED_IDENTIFIER 和 SET ANSI_NulLS 设置在执行存储过程时都将被忽略。在存储过程中出现的 SET QUOTED_IDENTIFIER 和 SET ANSI_NulLS 语句不影响存储过程的功能。
  
  其它 SET 选项(例如 SET ARITHABORT、SET ANSI_WARNINGS 或 SET ANSI_paddingS)在创建或更改存储过程时不保存。如果存储过程的逻辑取决于特定的设置,应在过程开

头添加一条 SET 语句,以确保设置正确。从存储过程中执行 SET 语句时,该设置只在存储过程完成之前有效。之后,设置将恢复为调用存储过程时的值。这使个别的客户端可以

设置所需的选项,而不会影响存储过程的逻辑。
  

说明 sql Server 是将空字符串解释为单个空格还是解释为真正的空字符串,由兼容级别设置控制。如果兼容级别小于或等于 65,sql Server 就将空字符串解释为单个空格。如

果兼容级别等于 70,则 sql Server 将空字符串解释为空字符串。
  获得有关存储过程的信息
  若要显示用来创建过程的文本,请在过程所在的数据库中执行 sp_helptext,并使用过程名作为参数。
  
  说明 
    使用 ENCRYPTION 选项创建的存储过程不能使用 sp_helptext 查看。
  若要显示有关过程引用的对象的报表,请使用 sp_depends。
  若要为过程重命名,请使用 sp_rename。

 
        引用对象
  sql Server 允许创建的存储过程引用尚不存在的对象。在创建时,只进行语法检查。执行时,如果高速缓存中尚无有效的计划,则编译存储过程以生成执行计划。只有在编译

过程中才解析存储过程中引用的所有对象。因此,如果语法正确的存储过程引用了不存在的对象,则仍可以成功创建,但在运行时将失败,因为所引用的对象不存在。
  延迟名称解析和兼容级别
  sql Server 允许 Transact-sql 存储过程在创建时引用不存在的表。这种能力称为延迟名称解析。不过,如果 Transact-sql 存储过程引用了该存储过程中定义的表,而兼容级别设置(通过执行 sp_dbcmptlevel 来设置)为 65,则在创建时会发出警告信息。而如果在运行时所引用的表不存在,将返回错误信息。
  执行存储过程
  成功执行 CREATE PROCEDURE 语句后,过程名称将存储在 sysobjects 系统表中,而 CREATE PROCEDURE 语句的文本将存储在 syscomments 中。第一次执行时,将编译该过程以确定检索数据的最佳访问计划。
  
  使用 cursor 数据类型的参数
  存储过程只能将 cursor 数据类型用于 OUTPUT 参数。如果为某个参数指定了 cursor 数据类型,也必须指定 varying 和 OUTPUT 参数。如果为某个参数指定了 varying 关键字,则数据类型必须是 cursor,并且必须指定 OUTPUT 关键字。
      
  说明 cursor 数据类型不能通过数据库 API(例如 olE DB、ODBC、ADO 和 DB-library)绑定到应用程序变量上。因为必须先绑定 OUTPUT 参数,应用程序才可以执行存储过

程,所以带有 cursor OUTPUT 参数的存储过程不能通过数据库 API 调用。只有将 cursor OUTPUT 变量赋值给 Transact-sql 局部 cursor 变量时,才可以通过 Transact-sql 批

处理、存储过程或触发器调用这些过程。
   
  Cursor 输出参数
  在执行过程时,以下规则适用于 cursor 输出参数:
  
  对于只进游标,游标的结果集中返回的行只是那些存储过程执行结束时处于或超出游标位置的行,例如:
  在过程中的名为 RS 的 100 行结果集上打开一个非滚动游标。
  过程提取结果集 RS 的头 5 行。
  过程返回到其调用者。
  返回到调用者的结果集 RS 由 RS 的第 6 到 100 行组成,调用者中的游标处于 RS 的第一行之前。
  对于只进游标,如果存储过程完成后,游标位于第一行的前面,则整个结果集将返回给调用批处理、存储过程或触发器。返回时,游标将位于第一行的前面。
  
  对于只进游标,如果存储过程完成后,游标的位置超出最后一行的结尾,则为调用批处理、存储过程或触发器返回空结果集。
  
  说明 空结果集与空值不同。
  
  对于可滚动游标,在存储过程执行结束时,结果集中的所有行均会返回给调用批处理、存储过程或触发器。返回时,游标保留在过程中最后一次执行提取时的位置。
  
  
  对于任意类型的游标,如果游标关闭,则将空值传递回调用批处理、存储过程或触发器。如果将游标指派给一个参数,但该游标从未打开过,也会出现这种情况。
  
  
  说明 关闭状态只有在返回时才有影响。例如,可以在过程中关闭游标,稍后再打开游标,然后将该游标的结果集返回给调用批处理、存储过程或触发器。
  
  
  临时存储过程
  sql Server 支持两种临时过程:局部临时过程和全局临时过程。局部临时过程只能由创建该过程的连接使用。全局临时过程则可由所有连接使用。局部临时过程在当前会话结束时自动除去。全局临时过程在使用该过程的最后一个会话结束时除去。通常是在创建该过程的会话结束时。
  
  临时过程用 # 和 ## 命名,可以由任何用户创建。创建过程后,局部过程的所有者是唯一可以使用该过程的用户。执行局部临时过程的权限不能授予其他用户。如果创建了全

局临时过程,则所有用户均可以访问该过程,权限不能显式废除。只有在 tempdb 数据库中具有显式 CREATE PROCEDURE 权限的用户,才可以在该数据库中显式创建临时过程(不

使用编号符命名)。可以授予或废除这些过程中的权限。
  
  注意: 频繁使用临时存储过程会在 tempdb 中的系统表上产生争用,从而对性能产生负面影响。建议使用 sp_executesql 代替。sp_executesql 不在系统表中存储数据,因此可以避免这一问题。

    自动执行存储过程
  sql Server 启动时可以自动执行一个或多个存储过程。这些存储过程必须由系统管理员创建,并在 sysadmin 固定服务器角色下作为后台过程执行。这些过程不能有任何输入

参数。
  
  对启动过程的数目没有限制,但是要注意,每个启动过程在执行时都会占用一个连接。如果必须在启动时执行多个过程,但不需要并行执行,则可以指定一个过程作为启动过

程,让该过程调用其它过程。这样就只占用一个连接。
  
  在启动时恢复了最后一个数据库后,即开始执行存储过程。若要跳过这些存储过程的执行,请将启动参数指定为跟踪标记 4022。如果以最低配置启动 sql Server(使用 -f

标记),则启动存储过程也不会执行。
  若要创建启动存储过程,必须作为 sysadmin 固定服务器角色的成员登录,并在 master 数据库中创建存储过程。
  
  使用 sp_procoption 可以:
  将现有存储过程指定为启动过程。停止在 sql Server 启动时执行过程。查看 sql Server 启动时执行的所有过程的列表。
 
  存储过程嵌套
  存储过程可以嵌套,即一个存储过程可以调用另一个存储过程。在被调用过程开始执行时,嵌套级将增加,在被调用过程执行结束后,嵌套级将减少。如果超出最大的嵌套级,会使整个调用过程链失败。可用 @@nesTLEVEL 函数返回当前的嵌套级。
  


存储过程示例
  A. 使用带有复杂 SELECT 语句的简单过程
  下面的存储过程从四个表的联接中返回所有作者(提供了姓名)、出版的书籍以及出版社。该存储过程不使用任何参数。
  
  USE pubs
  IF EXISTS (SELECT name FROM sysobjects
       WHERE name = \'au_info_all\' AND type = \'P\')
    DROP PROCEDURE au_info_all
  GO
  CREATE PROCEDURE au_info_all
  AS
  SELECT au_lname,au_fname,Title,pub_name
    FROM authors a INNER JOIN 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 name FROM sysobjects
       WHERE name = \'au_info\' AND type = \'P\')
    DROP PROCEDURE au_info
  GO
  USE pubs
  GO
  CREATE PROCEDURE au_info
    @lastname varchar(40),
    @firstname varchar(20)
  AS
  SELECT au_lname,pub_name
    FROM authors a INNER JOIN 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 name FROM sysobjects
     WHERE name = \'au_info2\' AND type = \'P\')
    DROP PROCEDURE au_info2
  GO
  USE pubs
  GO
  CREATE PROCEDURE au_info2
    @lastname varchar(30) = \'D%\',
    @firstname varchar(18) = \'%\'
  AS
  SELECT au_lname,pub_name
  FROM authors a INNER JOIN 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 name FROM sysobjects
     WHERE name = \'Titles_sum\' AND type = \'P\')
    DROP PROCEDURE Titles_sum
  GO
  USE pubs
  GO
  CREATE PROCEDURE Titles_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 @@TOTALCOST money
  EXECUTE Titles_sum \'The%\',@@TOTALCOST OUTPUT
  IF @@TOTALCOST < 200
  BEGIN
    PRINT \' \'
    PRINT \'All of these Titles can be purchased for less than $200.\'
  END
  ELSE
    SELECT \'The total cost of these Titles is $\'
       + RTRIM(CAST(@@TOTALCOST AS varchar(20)))
  
  下面是结果集:
  
  Title name                               
  ------------------------------------------------------------------------
  The Busy Executive\'s Database GuIDe
  The Gourmet Microwave
  The Psychology of Computer Cooking
  
  (3 row(s) affected)
  
  Warning,null value eliminated from aggregate.
  
  All of these Titles can be purchased for less than $200.
--------------------------------------------------------------------------------
E. 使用 OUTPUT 游标参数
  OUTPUT 游标参数用来将存储过程的局部游标传递回调用批处理、存储过程或触发器。
  
  首先,创建以下过程,在 Titles 表上声明并打开一个游标:
  
  USE pubs
  IF EXISTS (SELECT name FROM sysobjects
     WHERE name = \'Titles_cursor\' and type = \'P\')
  DROP PROCEDURE Titles_cursor
  GO
  CREATE PROCEDURE Titles_cursor @Titles_cursor CURSOR varying OUTPUT
  AS
  SET @Titles_cursor = CURSOR
  FORWARD_ONLY STATIC FOR
  SELECT *
  FROM Titles
  
  OPEN @Titles_cursor
  GO
  
  接下来,执行一个批处理,声明一个局部游标变量,执行上述过程以将游标赋值给局部变量,然后从该游标提取行。
  
  USE pubs
  GO
  DECLARE @MyCursor CURSOR
  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 name FROM sysobjects
     WHERE name = \'Titles_by_author\' AND type = \'P\')
    DROP PROCEDURE Titles_by_author
  GO
  CREATE PROCEDURE Titles_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 INNER JOIN 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 name FROM sysobjects
     WHERE name = \'encrypt_this\' AND type = \'P\')
    DROP PROCEDURE encrypt_this
  GO
  USE pubs
  GO
  CREATE PROCEDURE encrypt_this
  WITH ENCRYPTION
  AS
  SELECT *
  FROM authors
  GO
  
  EXEC sp_helptext encrypt_this
  
  下面是结果集:
  
  The object\'s comments have been encrypted.
  
  接下来,选择加密存储过程内容的标识号和文本。
  
  SELECT c.ID,c.text
  FROM syscomments c INNER 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 name FROM sysobjects
     WHERE name = \'sp_showindexes\' AND type = \'P\')
    DROP PROCEDURE sp_showindexes
  GO
  USE master
  GO
  CREATE PROCEDURE sp_showindexes
    @@table varchar(30) = \'sys%\'
  AS
  SELECT o.name AS table_name,
    i.name AS INDEX_name,
    indID AS INDEX_ID
  FROM sysindexes i INNER 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 name FROM sysobjects
     WHERE name = \'proc1\' AND type = \'P\')
    DROP PROCEDURE proc1
  GO
  -- Creating a procedure on a nonexistent table.
  USE pubs
  GO
  CREATE PROCEDURE proc1
  AS
    SELECT *
    FROM does_not_exist
  GO 
  -- Here is the statement to actually see the text of the procedure.
  SELECT o.ID,c.text
  FROM sysobjects o INNER JOIN syscomments c
    ON o.ID = c.ID
  WHERE o.type = \'P\' AND o.name = \'proc1\'
  GO
  USE master
  GO
  IF EXISTS (SELECT name FROM sysobjects
     WHERE name = \'proc2\' AND type = \'P\')
    DROP PROCEDURE proc2
  GO
  -- Creating a procedure that attempts to retrIEve information from a
  -- nonexistent column in an existing table.
  USE pubs
  GO
  CREATE PROCEDURE proc2
  AS
    DECLARE @mIDdle_init char(1)
    SET @mIDdle_init = NulL
    SELECT au_ID,mIDdle_initial = @mIDdle_init
    FROM authors
  GO 
  -- Here is the statement to actually see the text of the procedure.
  SELECT o.ID,c.text
  FROM sysobjects o INNER JOIN syscomments c
    ON o.ID = c.ID
  WHERE o.type = \'P\' and o.name = \'proc2\'

3. sql存储过程定义及小例子


    一、变量

    @I

    二、流程控制语句

    (if else | select case | while )
    Select ... CASE 实例
    DECLARE @iRet INT,@PKdisp VARCHAR(20)
    SET @iRet = '1'
    Select @iRet =
    CASE
        WHEN @PKdisp = '一' THEN 1
        WHEN @PKdisp = '二' THEN 2
        WHEN @PKdisp = '三' THEN 3
        WHEN @PKdisp = '四' THEN 4
        WHEN @PKdisp = '五' THEN 5
        ELSE 100
    END

    三、存储过程格式
        
    创建存储过程
    Create Proc dbo.存储过程名
    存储过程参数
    AS
    执行语句
    RETURN
    执行存储过程
    GO
*********************************************************/
-- 变量的声明,sql里面声明变量时必须在变量前加@符号
    DECLARE @I INT

-- 变量的赋值,变量赋值时变量前必须加set
    SET @I = 30

-- 声明多个变量
    DECLARE @s varchar(10),@a INT

-- sql 里if语句
    IF 条件 BEGIN
        执行语句
    END
    ELSE BEGIN
        执行语句
    END
           
    DECLARE @d INT
    set @d = 1

    IF @d = 1 BEGIN

    -- 打印
        PRINT '正确'
    END
    ELSE BEGIN
        PRINT '错误'
    END


-- sql 里的多条件选择语句.
    DECLARE @iRet INT,@PKdisp VARCHAR(20)
    SET @iRet = 1
    Select @iRet =
    CASE
        WHEN @PKdisp = '一' THEN 1
        WHEN @PKdisp = '二' THEN 2
        WHEN @PKdisp = '三' THEN 3
        WHEN @PKdisp = '四' THEN 4
        WHEN @PKdisp = '五' THEN 5
        ELSE 100
    END

-- 循环语句
    WHILE 条件 BEGIN   
        执行语句
    END

    DECLARE @i INT
    SET @i = 1
    WHILE @i<1000000 BEGIN
        set @i=@i+1
    END
    -- 打印
    PRINT @i


-- TruncATE 删除表中的所有行,而不记录单个行删除 *** 作,不能带条件

    /*
    TruncATE table 在功能上与不带 Where 子句的 Delete 语句相同:二者均删除表中的全部行

。但 TruncATE table 比 Delete 速度快,且使用的系统和事务日志资源少。
    Delete 语句每次删除一行,并在事务日志中为所删除的每行记录一项。TruncATE table 通过

释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。
    TruncATE table 删除表中的所有行,但表结构及其列、约束、索引等保持不变。新行标识所用

的计数值重置为该列的种子。如果想保留标识计数值,请改用 Delete。如果要删除表定义及其数据,请

使用 Drop table 语句。
    对于由 FOREIGN KEY 约束引用的表,不能使用 TruncATE table,而应使用不带 Where 子句的

Delete 语句。由于 TruncATE table 不记录在日志中,所以它不能激活触发器。
    TruncATE table 不能用于参与了索引视图的表。
    示例
        下例删除 authors 表中的所有数据。*/
       
        TruncATE table authors
              

-- Select INTO 从一个查询的计算结果中创建一个新表。 数据并不返回给客户端,这一点和普通的
-- Select 不同。 新表的字段具有和 Select 的输出字段相关联(相同)的名字和数据类型。
       
        select * into Newtable
            from Uname


-- Insert INTO Select
        -- 表ABC必须存在
        -- 把表Uname里面的字段Username复制到表ABC
        Insert INTO ABC Select Username FROM Uname

-- 创建临时表
        Create table #temp(
            UID int IDentity(1,1) PRIMARY KEY,
            Username varchar(16),
            Pwd varchar(50),
            Age smallint,
            Sex varchar(6)
        )
        -- 打开临时表
        Select * from #temp

-- 存储过程
        -- 要创建存储过程的数据库
        Use Test
        -- 判断要创建的存储过程名是否存在
            if Exists(Select name From sysobjects Where name='csp_AddInfo' And type='P')
            -- 删除存储过程
            Drop Procedure dbo.csp_AddInfo
        Go
                  
        -- 创建存储过程
        Create Proc dbo.csp_AddInfo
        -- 存储过程参数
        @Username varchar(16),
        @Pwd varchar(50),
        @Age smallint,
        @Sex varchar(6)
        AS
        -- 存储过程语句体
        insert into Uname (Username,Pwd,Age,Sex)
            values (@Username,@Pwd,@Age,@Sex)
        RETURN
        -- 执行
        GO
               
        -- 执行存储过程
        EXEC csp_AddInfo 'Junn.A','123456',20,'男'

4.存储过程应用案例

应用案例一:ASP留言板分页
本人用sql server 和asp写了一个简单的留言本,在不断的尝试中发现,分页显示留言的时候,不同的执行方式,时间上的一些差别。

下面通过对比来看看几种方式的用时对比。

一,使用存储过程分页,这种情况又分为两种方式:

 第一种,使用command对象,如下:

 Set Cmd=server.CreateObject("Adodb.Command")
 Cmd.ActiveConnection=conn
 Cmd.CommandText="ycuu_gb_getmsg"
 Cmd.CommandType=4'adCmdstoredProc
 cmd.prepared=true'
 set  param=Cmd.CreateParameter("@iPageNo",adInteger,1,2,Page)
 Cmd.Parameters.Append  param
 set  param=Cmd.CreateParameter("@iPageSize",PageSizeConst)
 Cmd.Parameters.Append  param
 set rs=Cmd.execute


 第二种,使用connection对象的执行方法直接执行,具体如下:

 set rs=conn.execute ("execute ycuu_gb_getmsg "&page&","&pagesizeConst)


二,不使用存储过程,直接使用ADODB.RecordSet的功能来分页,具体代码如下:

 Set rs = Server.CreateObject("ADODB.Recordset")
 sql = "Select * FROM Guestbook Order By dateandtime Desc"
 rs.open sql,conn,1
 rs.pagesize = 150'每页显示的留言数量,
 total = rs.RecordCount
 mypagesize = rs.pagesize
 rs.absolutepage = page

为了更加明显地显示出速度,我把每页显示的留言数量加大到150(事实上当然不会设置这么大的数值啦)。至于我机器的配置,就省略不说了,因为主要是速度对比。

发现,执行的时候时间分别如下:

第一种:稳定于0.1953125 秒到0.2109375 秒之间,平均值大概是:0.20秒

第二种:稳定于0.1716875 秒到0.1857秒之间,平均值大概是:0.177秒

第三种:稳定于0.4375 秒到0.4632秒之间,平均值大概是:0.45秒


但是,当读取的记录条数为20的时候,结果如下:
发现,执行的时候时间分别如下:

第一种:稳定于.0390625  秒到.0546875  秒之间,平均值大概是:0.045秒

第二种:稳定于0.046875  秒到.0546875 秒之间,平均值大概是:0.050秒

第三种:稳定于.09375 秒到0.1015625 秒之间,平均值大概是:0.97秒

在这样看来,似乎conn.execute和command.execute这两种方式似乎差别并不大,
而前者的调用方式好像更加简单一点。
同时,在这里可以看出分页的存储过程速度确实比recordset的分页速度要快很多。

 PS:对了,我还想问问各位大侠conn.execute和command.execute这两种方式中那种更加好的,呵呵,因为我在网上找到的都是后者这种方式执行存储过程的。

 
应用案例二:.NET 创建存储过程示例

一.前言

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

 本文将向大家介绍.NET数据库应用程序中存储过程的应用,以及如何将它与ADO.NET中的sqlDataAdapter对象、DataSet对象等结合使用以提高.NET数据库应用程序的总体性能。

一.系统要求

开发工具:Visual Studio.NET

数据库:sql Server 2005

二.创建一个简单的存储过程

这里我将向大家介绍如何运用Visual Studio.NET IDE来创建存储过程。运用Visual Studio.NET IDE创建存储过程是非常容易和直观的。

先建立一个数据库:db_test,然后建立一个表:卷烟销售表

CREATE table 卷烟库存表
(
卷烟品牌 VARCHAR(40) PRIMARY KEY NOT NulL,
库存数量 INT NulL,
库存单价 MONEY NulL,
库存金额 MONEY NulL
)

你只要在服务器资源管理器中导向到db_test数据库并展开节点,就会发现包括存储过程在内的各种数据库对象。

在存储过程节点上点击右键便可d出一个菜单,其中包含了“新建存储过程”的命令。

下面我们就来创建一个简单的不带参数的存储过程并运用之:

ALTER PROCEDURE dbo.Get_卷烟库存表
AS
 SELECT 卷烟品牌,库存数量,库存单价,库存金额
FROM 卷烟库存表
 
 RETURN
 

 创建以上存储过程后,保存之。保存完毕,与该存储过程相对应的节点就会出现在服务器资源管理器中。同时请注意代码编辑窗口中的CREATE关键字变为ALTER关键字了,该关键字

是用于更改任何现有的存储过程的。要运行上述存储过程,只要点击其节点并在右键d出菜单中选择“运行存储过程。 

三.创建一个带参数的存储过程

以上我们创建了一个简单的不带参数的存储过程,而在实际的应用中往往会用到很多带有参数的存储过程。带有参数的存储过程一般是用于更新数据或是插入数据的。下面我们可

以运用同样的 *** 作方法创建一个带参数的存储过程: 

CREATE PROCEDURE dbo.Update_卷烟库存表
 (
  @卷烟品牌 varchar(40),
  @库存数量 int,
  @库存单价 money,
  @库存金额 money
 )
AS
 update 卷烟库存表 set 库存数量=@库存数量,库存单价=@库存单价,库存金额=@库存金额
 where 卷烟品牌=@卷烟品牌
 
 RETURN
 
在上面的创建存储过程的代码中,我们通过在名称前添加一个“@”标志来声明存储过程的局部变量-参数,同时还声明了各个参数的类型,确定了各个参数的方向值,也即表明该

参数是输入型的还是输出型的或者是输入输出型的或者是返回值型的。用户通过相应的存储过程名称以及正确有效的参数便可调用该存储过程了。还有,你可以通过运用OUTPUT关键字在参数中添加输出型的参数。

  四.根据参数查询存储过程返回结果集

   要求:根据输入参数“卷烟品牌”,得到它在卷烟库存表中的库存数量。并返回影响行数。

    1、创建存储过程“Get_卷烟库存表_By品牌”

CREATE PROCEDURE dbo.Get_卷烟库存表_By品牌
 (
 @卷烟品牌  varchar(40),
 @Rowcount int OUTPUT
 )
 
AS
 /* SET NOCOUNT ON */
 SELECT 卷烟品牌,库存金额
FROM 卷烟库存表 where 卷烟品牌=@卷烟品牌

    set @Rowcount=@@ROWCOUNT
 
 RETURN
 

    2、asp.net调用存储过程

  添加引用:
using System.Data;
using System.Data.sqlClIEnt;

 protected voID Page_Load(object sender,EventArgs e)
    {
        DataSet ds = new DataSet();


        sqlConnection conn = new sqlConnection("Data Source=.;Initial Catalog=db_test;User ID=bmsadmin;Password=bmsadmin");

        if (conn.State != ConnectionState.Open)
        {
            conn.open();
        }

        sqlCommand cmd = new sqlCommand("Get_卷烟库存表_By品牌",conn);
        cmd.CommandType = CommandType.StoredProcedure;

        //添加输入查询参数、赋予值
        cmd.Parameters.Add("@卷烟品牌",sqlDbType.VarChar,40);
        cmd.Parameters["@卷烟品牌"].Value = "玉溪";

        //添加输出参数
        cmd.Parameters.Add("@rowcount",sqlDbType.Int);
        cmd.Parameters["@rowcount"].Direction = ParameterDirection.Output;

        cmd.ExecuteNonquery();

        sqlDataAdapter dataAdapter = new sqlDataAdapter();
        dataAdapter.SelectCommand = cmd;
        if (dataAdapter != null)
        {
            dataAdapter.Fill(ds);
        }

        //得到存储过程输出参数
        String rowcount = cmd.Parameters["@rowcount"].Value.ToString();
 

    说明:这个只是示意说明如何取得输出值,此处返回所有结果值效率底下,不可以采用。

 

应用案例三:分页存储过程示例

set  ANSI_NulLS  ON

set  QUOTED_IDENTIFIER  ON

go







ALTER   PROCEDURE   [ dbo ] . [ PROCE_sql2005PAGECHANGE ]

(

 
@tablename   varchar ( 50 ),             -- 表名

  @ReFIEldsstr   varchar ( 200 =   ' * ' ,    -- 字段名(全部字段为*)

  @OrderString   varchar ( 200 ),          -- 排序字段(必须!支持多字段不用加order by)

  @WhereString   varchar ( 500 = N '' ,   -- 条件语句(不用加where)

  @PageSize   int ,                      -- 每页多少条记录

  @PageIndex   int   =   1  ,                -- 指定当前为第几页

  @TotalRecord   int  output             -- 返回总记录数

)

AS

 

BEGIN     


    
-- 处理开始点和结束点

     Declare   @StartRecord   int ;

    
Declare   @EndRecord   int

    
Declare   @TotalCountsql   nvarchar ( 500 ); 

    
Declare   @sqlString   nvarchar ( 2000 );    

    
set   @StartRecord   =  ( @PageIndex - 1 ) * @PageSize   +   1

    
set   @EndRecord   =   @StartRecord   +   @PageSize   -   1  

    
SET   @TotalCountsql =  N ' select @TotalRecord = count(*) from  '   +   @tablename ; -- 总记录数语句

     SET   @sqlString   =  N ' (select row_number() over (order by  ' +   @OrderString   + ' ) as rowID, ' + @ReFIEldsstr + '  from  ' +   @tablename ; -- 查询语句

     --

     IF  ( @WhereString =   ''   or   @WhereString != null )

        
BEGIN

            
SET   @TotalCountsql = @TotalCountsql   +   '   where  ' +   @WhereString ;

            
SET   @sqlString   = @sqlString +   '   where  ' +   @WhereString ;            

        
END

    
-- 第一次执行得到

     -- IF(@TotalRecord is null)

     --    BEGIN

            EXEC  sp_executesql  @totalCountsql ,N ' @TotalRecord int out ' , @TotalRecord  output; -- 返回总记录数

     --   END

     -- --执行主语句

     set   @sqlString   = ' select * from  '   +   @sqlString   +   ' ) as t where rowID between  '   +   ltrim ( str ( @StartRecord ))  +   '  and  '   +    ltrim ( str ( @EndRecord ));

    
Exec ( @sqlString )    

END

    






 

 

附加资料:

存储过程实例

存储过程入门

 ASP.NET调用存储过程带(输入/输出)参数和返回值的例子

总结

以上是内存溢出为你收集整理的存储过程原理与案例全部内容,希望文章能够帮你解决存储过程原理与案例所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/1181653.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-02
下一篇 2022-06-02

发表评论

登录后才能评论

评论列表(0条)

保存