• SQL必需掌握的100个重要知识点:使用存储过程


    19.1 存储过程
    迄今为止,我们使用的大多数 SQL语句都是针对一个或多个表的单条语
    句。并非所有操作都这么简单,经常会有一些复杂的操作需要多条语句
    才能完成,例如以下的情形。
      为了处理订单,必须核对以保证库存中有相应的物品。
      如果物品有库存,需要预定,不再出售给别的人,并且减少物品数据
    以反映正确的库存量。
      库存中没有的物品需要订购,这需要与供应商进行某种交互。
      关于哪些物品入库(并且可以立即发货)和哪些物品退订,需要通知
    相应的顾客。
    这显然不是一个完整的例子,它甚至超出了本书中所用样例表的范围,
    但足以表达我们的意思了。执行这个处理需要针对许多表的多条 SQL语
    句。此外,需要执行的具体 SQL语句及其次序也不是固定的,它们可能
    会根据物品是否在库存中而变化。

    那么,怎样编写代码呢?可以单独编写每条 SQL语句,并根据结果有条
    件地执行其他语句。在每次需要这个处理时(以及每个需要它的应用中),
    都必须做这些工作。
    可以创建存储过程。简单来说,存储过程就是为以后使用而保存的一条
    或多条 SQL语句。可将其视为批文件,虽然它们的作用不仅限于批处理。
    说明:不适用于 SQLite
    SQLite不支持存储过程。
    说明:还有更多内容
    存储过程很复杂,全面介绍它需要很大篇幅。市面上有专门讲存储过
    程的书。本课不打算讲解存储过程的所有内容,只给出简单介绍,让
    读者对它们的功能有所了解。因此,这里给出的例子只提供 Oracle和
    SQL Server的语法。
    19.2 为什么要使用存储过程
    我们知道了什么是存储过程,那么为什么要使用它们呢?理由很多,下
    面列出一些主要的。
      通过把处理封装在一个易用的单元中,可以简化复杂的操作(如前面
    例子所述)。
      由于不要求反复建立一系列处理步骤,因而保证了数据的一致性。如
    果所有开发人员和应用程序都使用同一存储过程,则所使用的代码都
    是相同的。
      上一点的延伸就是防止错误。需要执行的步骤越多,出错的可能性就
    越大。防止错误保证了数据的一致性。

      简化对变动的管理。如果表名、列名或业务逻辑(或别的内容)有变
    化,那么只需要更改存储过程的代码。使用它的人员甚至不需要知道
    这些变化。
      上一点的延伸就是安全性。通过存储过程限制对基础数据的访问,减
    少了数据讹误(无意识的或别的原因所导致的数据讹误)的机会。
      因为存储过程通常以编译过的形式存储,所以 DBMS处理命令所需的
    工作量少,提高了性能。
      存在一些只能用在单个请求中的 SQL元素和特性,存储过程可以使用
    它们来编写功能更强更灵活的代码。
    换句话说,使用存储过程有三个主要的好处,即简单、安全、高性能。
    显然,它们都很重要。不过,在将 SQL代码转换为存储过程前,也必须
    知道它的一些缺陷。
      不同 DBMS中的存储过程语法有所不同。事实上,编写真正的可移植
    存储过程几乎是不可能的。不过,存储过程的自我调用(名字以及数
    据如何传递)可以相对保持可移植。因此,如果需要移植到别的DBMS,
    至少客户端应用代码不需要变动。
      一般来说,编写存储过程比编写基本 SQL语句复杂,需要更高的技能,
    更丰富的经验。因此,许多数据库管理员把限制存储过程的创建作为
    安全措施(主要受上一条缺陷的影响)。
    尽管有这些缺陷,存储过程还是非常有用的,并且应该使用。事实上,
    多数 DBMS都带有用于管理数据库和表的各种存储过程。更多信息请参
    阅具体的 DBMS文档。

    说明:不会写存储过程?你依然可以使用
    大多数 DBMS将编写存储过程所需的安全和访问权限与执行存储过
    程所需的安全和访问权限区分开来。这是好事情,即使你不能(或
    不想)编写自己的存储过程,也仍然可以在适当的时候执行别的存
    储过程。
    19.3 执行存储过程
    存储过程的执行远比编写要频繁得多,因此我们先介绍存储过程的执行。
    执行存储过程的 SQL语句很简单,即 EXECUTE 。 EXECUTE 接受存储过程
    名和需要传递给它的任何参数。请看下面的例子(你无法运行这个例子,
    因为 AddNewProduct 这个存储过程还不存在):
    输入▼
    EXECUTE AddNewProduct('JTS01',
    'Stuffed Eiffel Tower',
    6.49,
    'Plush stuffed toy with
    ➥the text La Tour Eiffel in red white and blue');
    分析▼
    这里执行一个名为 AddNewProduct 的存储过程,将一个新产品添加到
    Products 表中。 AddNewProduct 有四个参数,分别是:供应商 ID
    ( Vendors 表的主键)、产品名、价格和描述。这 4 个参数匹配存储过程
    中 4个预期变量(定义为存储过程自身的组成部分)。此存储过程将新行
    添加到 Products 表,并将传入的属性赋给相应的列。
    我们注意到,在 Products 表中还有另一个需要值的列 prod_id 列,它
    是这个表的主键。为什么这个值不作为属性传递给存储过程?要保证恰

    当地生成此 ID,最好是使生成此 ID 的过程自动化(而不是依赖于最终
    用户的输入)。这也是这个例子使用存储过程的原因。以下是存储过程所
    完成的工作:
      验证传递的数据,保证所有 4个参数都有值;
      生成用作主键的唯一 ID;
      将新产品插入 Products 表,在合适的列中存储生成的主键和传递的
    数据。
    这就是存储过程执行的基本形式。对于具体的 DBMS,可能包括以下的
    执行选择。
      参数可选,具有不提供参数时的默认值。
      不按次序给出参数,以“参数=值”的方式给出参数值。
      输出参数,允许存储过程在正执行的应用程序中更新所用的参数。
      用 SELECT 语句检索数据。
      返回代码,允许存储过程返回一个值到正在执行的应用程序。
    19.4 创建存储过程
    正如所述,存储过程的编写很重要。为了获得感性认识,我们来看一个简
    单的存储过程例子,它对邮件发送清单中具有邮件地址的顾客进行计数。
    下面是该过程的 Oracle版本:
    输入▼
    CREATE PROCEDURE MailingListCount (
    ListCount OUT INTEGER
    )

    IS
    v_rows INTEGER;
    BEGIN
    SELECT COUNT(*) INTO v_rows
    FROM Customers
    WHERE NOT cust_email IS NULL;
    ListCount := v_rows;
    END;
    分析▼
    这个存储过程有一个名为 ListCount 的参数。此参数从存储过程返回一
    个值而不是传递一个值给存储过程。关键字 OUT 用来指示这种行为。
    Oracle支持 IN (传递值给存储过程)、 OUT (从存储过程返回值,如这里)、
    INOUT (既传递值给存储过程也从存储过程传回值)类型的参数。存储
    过程的代码括在 BEGIN 和 END 语句中,这里执行一条简单的 SELECT 语
    句,它检索具有邮件地址的顾客。然后用检索出的行数设置 ListCount
    (要传递的输出参数)。
    调用 Oracle例子可以像下面这样:
    输入▼
    var ReturnValue NUMBER
    EXEC MailingListCount(:ReturnValue);
    SELECT ReturnValue;
    分析▼
    这段代码声明了一个变量来保存存储过程返回的任何值,然后执行存储
    过程,再使用 SELECT 语句显示返回的值。
    下面是该过程的 SQL Server 版本。

    输入▼
    CREATE PROCEDURE MailingListCount
    AS
    DECLARE @cnt INTEGER
    SELECT @cnt = COUNT(*)
    FROM Customers
    WHERE NOT cust_email IS NULL;
    RETURN @cnt;
    分析▼
    此存储过程没有参数。调用程序检索 SQL Server的返回代码提供的值。
    其中用 DECLARE 语句声明了一个名为 @cnt 的局部变量(SQL Server中所
    有局部变量名都以 @ 起头);然后在 SELECT 语句中使用这个变量,让它
    包含 COUNT() 函数返回的值;最后,用 RETURN @cnt 语句将计数返回给
    调用程序。
    调用 SQL Server例子可以像下面这样:
    输入▼
    DECLARE @ReturnValue INT
    EXECUTE @ReturnValue=MailingListCount;
    SELECT @ReturnValue;
    分析▼
    这段代码声明了一个变量来保存存储过程返回的任何值,然后执行存储
    过程,再使用 SELECT 语句显示返回的值。
    下面是另一个例子,这次在 Orders 表中插入一个新订单。此程序仅适
    用于 SQL Server,但它说明了存储过程的某些用途和技术:

    输入▼
    CREATE PROCEDURE NewOrder @cust_id CHAR(10)
    AS
    -- 为订单号声明一个变量
    DECLARE @order_num INTEGER
    -- 获取当前最大订单号
    SELECT @order_num=MAX(order_num)
    FROM Orders
    -- 决定下一个订单号
    SELECT @order_num=@order_num+1
    -- 插入新订单
    INSERT INTO Orders(order_num, order_date, cust_id)
    VALUES(@order_num, GETDATE(), @cust_id)
    -- 返回订单号
    RETURN @order_num;
    分析▼
    此存储过程在 Orders 表中创建一个新订单。它只有一个参数,即下订
    单顾客的 ID。订单号和订单日期这两列在存储过程中自动生成。代码首
    先声明一个局部变量来存储订单号。接着,检索当前最大订单号(使用
    MAX() 函数)并增加 1(使用 SELECT 语句)。然后用 INSERT 语句插入由
    新生成的订单号、当前系统日期(用 GETDATE() 函数检索)和传递的顾
    客 ID组成的订单。最后,用 RETURN @order_num 返回订单号(处理订
    单物品需要它)。请注意,此代码加了注释,在编写存储过程时应该多加
    注释。
    说明:注释代码
    应该注释所有代码,存储过程也不例外。增加注释不影响性能,因此
    不存在缺陷(除了增加编写时间外)。注释代码的好处很多,包括使别
    人(以及你自己)更容易地理解和更安全地修改代码。

    对代码进行注释的标准方式是在之前放置 -- (两个连字符)。有的
    DBMS还支持其他的注释语法,不过所有 DBMS都支持 -- ,因此在注
    释代码时最好都使用这种语法。
    下面是相同 SQL Server代码的一个很不同的版本:
    输入▼
    CREATE PROCEDURE NewOrder @cust_id CHAR(10)
    AS
    -- 插入新订单
    INSERT INTO Orders(cust_id)
    VALUES(@cust_id)
    -- 返回订单号
    SELECT order_num = @@IDENTITY;
    分析▼
    此存储过程也在 Orders 表中创建一个新订单。这次由 DBMS 生成订单
    号。大多数 DBMS都支持这种功能;SQL Server中称这些自动增量的列
    为标识字段(identity field),而其他 DBMS称之为自动编号(auto number)
    或序列(sequence)。传递给此过程的参数也是一个,即下订单的顾客 ID。
    订单号和订单日期没有给出,DBMS 对日期使用默认值( GETDATE() 函
    数),订单号自动生成。怎样才能得到这个自动生成的 ID?在 SQL Server
    上可在全局变量 @@IDENTITY 中得到,它返回到调用程序(这里使用
    SELECT 语句)。
    可以看到,借助存储过程,可以有多种方法完成相同的工作。不过,所
    选择的方法受所用 DBMS特性的制约。

  • 相关阅读:
    【一起学数据结构与算法】时间复杂度_空间复杂度
    软件测试面试真题 | 黑盒测试和白盒测试的基本概念是什么?
    为什么混合云是未来云计算的主流形态?
    C语言入门这一篇就够了-肝(中)
    YOLO算法改进Backbone系列之:EfficientViT
    Redis-05Redis应用场景
    刷穿力扣(1~30)
    redis我记不住的那些命令(六)
    【Linux学习笔记】 - 常用指令学习及其验证(上)
    svn文件不显示红色感叹号
  • 原文地址:https://blog.csdn.net/tysonchiu/article/details/125525359