第六章SQL数据库开发--TSQL—储存过程

第六章SQL数据库开发--TSQL—储存过程

 

6.1 TSQL-存储过程说明

存储过程 (Stored Procedure) 是在大型数据库系统中 , 一组为了完成特定功能的 SQL 语句集 , 存储在数据库中 , 经过第一次编译后再次调用不需要再次编译 , 用户通过指定存储过程的名字并给出参数 (如果该存储过程带有参数) 来执行它 , 存储过程是数据库中的一个重要对象 ;

1 接受输入参数并以输出参数的格式向调用程序返回多个值。

2 包含用于在数据库中执行操作的编程语句。 这包括调用其他过程。

3 向调用程序返回状态值,以指明成功或失败(以及失败的原因)。

6.1.1 存储过程的优点:

存储过程加快系统运行速度,存储过程只在创建时编译,以后每次执行时不需要重新编译。

存储过程可以封装复杂的数据库操作,简化操作流程,例如对多个表的更新,删除等。

可实现模块化的程序设计,存储过程可以多次调用,提供统一的数据库访问接口,改进应用程序的可维护性。

存储过程可以增加代码的安全性,对于用户不能直接操作存储过程中引用的对象,SQL  Server可以设定用户对指定存储过程的执行权限。

存储过程可以降低网络流量,存储过程代码直接存储于数据库中,在客户端与服务器的通信过程中,不会产生大量的T_SQL代码流量。

存储过程的缺点:

数据库移植不方便,存储过程依赖与数据库管理系统, SQL Server 存储过程中封装的操作代码不能直接移植到其他的数据库管理系统中。

不支持面向对象的设计,无法采用面向对象的方式将逻辑业务进行封装,甚至形成通用的可支持服务的业务逻辑框架.

代码可读性差,不易维护。不支持集群。

6.1.2 存储过程分类

用户定义

用户定义的过程可在用户定义的数据库中创建,或者在除了 Resource 数据库之外的所有系统数据库中创建。 该过程可在 Transact-SQL 中开发,或者作为对 Microsoft .NET Framework 公共语言运行时 (CLR) 方法的引用开发。

临时

临时过程是用户定义过程的一种形式。 临时过程与永久过程相似,只是临时过程存储于 tempdb中。 临时过程有两种类型:本地过程和全局过程。 它们在名称、可见性以及可用性上有区别。 本地临时过程的名称以单个数字符号 (#) 开头;它们仅对当前的用户连接是可见的;当用户关闭连接时被删除。 全局临时过程的名称以两个数字符号 (##) 开头,创建后对任何用户都是可见的,并且在使用该过程的最后一个会话结束时被删除。

系统

系统过程是 SQL Server随附的。 它们物理上存储在内部隐藏的 Resource 数据库中,但逻辑上出现在每个系统定义数据库和用户定义数据库的 sys 架构中。 此外, msdb 数据库还在 dbo 架构中包含用于计划警报和作业的系统存储过程。 因为系统过程以前缀 sp_ 开头,所以,我们建议你在命名用户定义过程时不要使用此前缀。

6.2 建立与修改存储过程

  CREATE [ OR ALTER ] { PROC | PROCEDURE }

    [schema_name.] procedure_name [ ; number ]  

    [ { @parameter [ type_schema_name. ] data_type } 

        [ VARYING ] [ = default ] [ OUT | OUTPUT | [READONLY] 

    ] [ ,...n ]  

[ WITH <procedure_option> [ ,...n ] ] 

[ FOR REPLICATION ]  

AS { [ BEGIN ] sql_statement [;] [ ...n ] [ END ] } 

[;] 

 

<procedure_option> ::=  

    [ ENCRYPTION ] 

    [ RECOMPILE ] 

    [ EXECUTE AS Clause ] 

 

简写语法

  CREATE [ OR ALTER ] { PROC | PROCEDURE }

    [schema_name.] procedure_name [ ; number ]  

    [ { @parameter [ type_schema_name. ] data_type } 

        [ VARYING ] [ = default ] [ OUT | OUTPUT | [READONLY] 

    ] [ ,...n ]  

AS { [ BEGIN ] sql_statement [;] [ ...n ] [ END ] } 

 

CREATE  PROC 关键字

procedure_name 存储过程名称

number  对存储过程进行分组

@parameter  存错过程参数

data_type     数据类型

VARYING  指定作为输出参数支持的结果集,改参数仅适用于游标参数。

Default 可选项,参数默认值

OUTPUT  将参数返回值给调用的过程

AS  制定存储过程的操作

SQL_STATEMENT 存储过程的过程体。

举例

 

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROCEDURE <Procedure_Name, sysname, ProcedureName>

         -- Add the parameters for the stored procedure here

         <@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>,

         <@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>

AS

BEGIN

         -- SET NOCOUNT ON added to prevent extra result sets from

         -- interfering with SELECT statements.

         SET NOCOUNT ON;

 

    -- Insert statements for procedure here

         SELECT <@Param1, sysname, @p1>, <@Param2, sysname, @p2>

END

GO

 

6.2.1 建立与修改存储过程说明

6.2.1.1 ANSI_NULLS

当ANSI_NULLS 为ON时,遵循SQL92的标准,只能使用IS NULL 来判断值是否为NULL, 而不能使用=或<>来与NULL做比较,任何值包括NULL值与NULL值做=或<>运算都得到FALSE。

 

当ANSI_NULLS为OFF时,将不再遵循SQL92标准,可以使用=和<>来与NULL做BOOL运算。

 

6.2.1.2 QUOTED_IDENTIFIER

当SET QUOTED_IDENTIFIER值为ON时,双引号内的字符被当作是数据库对象。就是说双引号" "和标识符[]效果是一样样的,他们都表示引用的字符是数据库对象。单引号'表示字符串的边界。

  当SET QUOTDE_IDENTIFIER OFF时,双引号被解释为字符串的边界,和单引号的作用是类似的。就是说双引号"不能当做标识符使用,但是可以当做字符边界,和单引号'的效果是一样样的。

  可以做一个总结:当SET QUOTED_IDENTIFIER ON " "等同于[ ] 表示数据库对象;当SET QUOTED_IDENTIFIER OFF " "等同于' '表示字符串边界;还有这里的双引号" 并不是两个单引号'合起来的,是shift+”打出来的,初学者可能会犯这样的错误。

6.2.1.3 SET NOCOUNT

SET NOCOUNT

使返回的结果中不包含有关受 Transact-SQL 语句影响的行数的信息。

 

语法

SET NOCOUNT { ON | OFF }

 

注释

当 SET NOCOUNT 为 ON 时,不返回计数(表示受 Transact-SQL 语句影响的行数)。当 SET NOCOUNT 为 OFF 时,返回计数。

 

即使当 SET NOCOUNT 为 ON 时,也更新 @@ROWCOUNT 函数。

6.2.2 建立存储过程

6.2.2.1 建立参数输入的存储过程

USE [T_BRANCH]

GO

 

/****** Object:  StoredProcedure [dbo].[ZH_Proc_Insert_M02_VERSION_SYJ ]    Script Date: 2018/12/5 21:38:53 ******/

SET ANSI_NULLS ON

GO

 

SET QUOTED_IDENTIFIER ON

GO

 

CREATE PROC [dbo].[ZH_Proc_Insert_M02_VERSION_SYJ ]

@PLAZA_ID int,

@LANE_ID int,

@TABLE_ID INT,

@VERSION VARCHAR(50),

@CURENT_TIME VARCHAR(50)

AS

BEGIN

BEGIN TRY

           BEGIN

 

          INSERT INTO [dbo].[M02_VERSION_SYJ]

                                ([PLAZA_ID]

                                ,[LANE_ID]

                                ,[TABLE_ID]

                                ,[VERSION]

                                ,[CURENT_TIME])

                     VALUES

                                (@PLAZA_ID ,

                                      @LANE_ID ,

                                               @TABLE_ID,                                                                                                              @VERSION,

                                      @CURENT_TIME )

 

         END

END TRY

 

BEGIN CATCH

          BEGIN    

                    IF @@Error = 2627 goto  Repeat

                    else goto  ErrMsg

          END

END CATCH

         

 

SELECT 1 AS RESULT, '执行成功!' AS WARNING

RETURN 1;

 

Repeat:   

          BEGIN

                    UPDATE [dbo].[M02_VERSION_SYJ] SET VERSION = @VERSION ,[CURENT_TIME] = @CURENT_TIME

            WHERE [PLAZA_ID] = @PLAZA_ID and [LANE_ID] = @LANE_ID and [TABLE_ID] = @TABLE_ID

                    IF @@Error <> 0 or @@rowcount = 0 goto ErrMsg

                    SELECT 2 AS RESULT, '进行更新!' AS WARNING

                    RETURN 2   --进行更新

          END

 

ErrMsg:   

          BEGIN

                   

                    SELECT @@Error

                    SELECT -1 AS RESULT, '更新失败!' AS WARNING

                    RETURN -1   --添加失败并回滚

          END

END

GO

 

6.2.2.2 建立参数输出的存储过程 (缺)

       带参数输出的存储过程,主要是给调用程序返回值。

6.2.2.3  WITH ENCRYPTION 执行加密的存储过程

CREATE PROCEDURE HumanResources.uspEncryptThis 

WITH ENCRYPTION 

AS 

    SET NOCOUNT ON

    SELECT BusinessEntityID, JobTitle, NationalIDNumber,

        VacationHours, SickLeaveHours  

    FROM HumanResources.Employee; 

GO 

HumanResources.Employee 表是加密的,只有使用WITH ENCRYPTION选项,才可以执行成功。

 

6.3 存储过程错误处理

  6.3.1 利用@@ERROR处理错误

  返回执行的上一个 Transact-SQL 语句的错误号,没有错误,执行成功,则返回 0

 

@@ERROR不等于0,就是存储过程执行失败。@@ERROR=2627  解释就是不能插入重复键。

       BEGIN TRY

        begin

          

           INSERT INTO [L01_EVENTS]([MID],[PLAZA_ID],[LANE_ID],[OP_ID],[TIME_BEGIN],[OCCUR_TIME ],[SHIFT_ID],[EVENT_TYPE],[SEND_FLAG])

               VALUES (@MID ,@PLAZA_ID ,@LANE_ID ,@OP_ID,@TIME_BEGIN,@OCCUR_TIME,@SHIFT_ID ,@EVENT_TYPE ,@SEND_FLAG)

 

 

       END

    END TRY

    BEGIN CATCH

       BEGIN 

           IF @@Error = 2627 goto  Repeat

           else goto  ErrMsg

  6.3.2 使用TRY...CATCH块处理错误

Transact-SQL 语句组可以包含在 TRY 块中。 如果 TRY 块内部发生错误,则会将控制传递给 CATCH 块中包含的另一个语句组。

语法

BEGIN TRY 

     { sql_statement | statement_block } 

END TRY 

BEGIN CATCH 

     [ { sql_statement | statement_block } ] 

END CATCH 

[ ; ] 

 

使用条件

1 TRY…CATCH 构造可对严重程度高于 10 但不关闭数据库连接的所有执行错误进行缓存。

2 TRY 块后必须紧跟相关联的 CATCH 块。 在 END TRY 和 BEGIN CATCH 语句之间放置任何其他语句都将生成语法错误。

3 TRY…CATCH 构造不能跨越多个批处理。 TRY…CATCH 构造不能跨越多个 Transact-SQL 语句块。 例如,TRY…CATCH 构造不能跨越 Transact-SQL 语句的两个 BEGIN…END 块,且不能跨越 IF…ELSE 构造。

4 1119级别错误时,SQL才会立即对出TRY并转向CATCH块,

 

ERROR_NUMBER() 返回错误编号。

ERROR_SEVERITY() 返回严重性。

ERROR_STATE() 返回错误状态号。

ERROR_PROCEDURE() 返回出现错误的存储过程或触发器的名称。

ERROR_LINE() 返回导致错误的例程中的行号。

ERROR_MESSAGE()

 

 

错误级别

错误信息

描述

1-10

只是信息错误

这包括了上下文的更改,如调整了设置或者聚合运算时出现了NULL,这些不会触发CATCH块,因此如果需要测试这个错误级别,需要手动使用@@ERROR

11-19

相对严重错误

这些大多数时由于代码处理的错误(例如主键和外键)。有些错误比较严重,你可能不希望继续处理(例如超出内存错误),但至少可以捕捉他们并适当退出

20-25

非常严重

这些错误通常为系统级错误,因此脚本和连接将立即终止

 

      BEGIN TRY

              BEGIN

 

             INSERT INTO [dbo].[M02_VERSION_PARAM]

                              ([PLAZA_ID]

                              ,[LANE_ID]

                              ,[TABLE_ID]

                              ,[TABLE_NAME]

                              ,[Effect_VERSION]

                              ,[NotEffect_VERSION]

                              ,[CURENT_TIME])

                     VALUES

                              (@PLAZA_ID ,

                                  @LANE_ID ,

                                  @TABLE_ID,

                                  @TABLE_NAME ,

                                  @Effect_VERSION,

                                  @NotEffect_VERSION,

                                  @CURENT_TIME )

 

END

      END TRY

 

      BEGIN CATCH

             BEGIN  

                    IF @@Error = 2627 goto  Repeat ##插入重复行

                    else goto  ErrMsg

             END

      END CATCH

 

 

 6.4 执行存储过程

   6.4.1 带参数存储过程

简写

EXEC ZH_Proc_Insert_M02_VERSION_SYJ 100891,     4,    151101,       1812050000220717,       '2018-12-05 10:31:17';

2    进行更新!

 

复杂写法带参数名称

EXEC ZH_Proc_Insert_M02_VERSION_SYJ @PLAZA_ID=100891,   @LANE_ID=100,       @TABLE_ID=151101,     @VERSION=1812050000220717,     @CURENT_TIME='2018-12-05 10:31:17';

  1. 执行成功!

 

 

发布了37 篇原创文章 · 获赞 0 · 访问量 2428

猜你喜欢

转载自blog.csdn.net/syjhct/article/details/84994961
今日推荐