MySQL基础——视图和存储过程

视图

视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。

什么是视图

在之前的笔记中有个例子:检索订购了‘TNT2’的客户的信息:

mysql> SELECT cust_name, cust_contact
    -> FROM customers, orders, orderitems
    -> WHERE customers.cust_id = orders.cust_id
    ->   AND orders.order_num = orderitems.order_num
    ->   AND orderitems.prod_id = 'TNT2';
+----------------+--------------+
| cust_name      | cust_contact |
+----------------+--------------+
| Coyote Inc.    | Y Lee        |
| Yosemite Place | Y Sam        |
+----------------+--------------+

任何需要这个数据的人必须理解相关表的结构,并且知道如何创建查询和联结表。现在,把整个查询包装秤一个名为productcustomers的虚拟表,让一切变得轻松了:

mysql> SELECT cust_name, cust_contact
    -> FROM productcustomers
    -> WHERE prod_id = 'TNT2'

使用视图的好处:

  • 重用SQL语句
  • 简化复杂的SQL操作
  • 使用表的组成部分而不是整个表
  • 保护数据
  • 更改数据格式和表示。视图可以返回与底层表的表示和格式不同的数据
视图的规则和限制
  • 与表一样,视图必须唯一命名
  • 对于可以创建的视图数目没有限制
  • 为了创建视图,必须具有足够的访问权限。
  • 视图可以嵌套。
  • ORDER BY可以用在视图中,但如果从该视图检索数据SELECT中也包含有ORDER BY,那么该视图中的ORDER BY将被覆盖。
  • 视图不能索引,也不能有关联的触发器或默认值。
  • 视图可以和表一起使用。
使用视图
  • 视图用CREAT VIEW 语句来创建
  • 使用SHOW CREAT VIEW viewname; 来查看创建视图的语句。
  • DROP删除视图,其语法为DROP VIEW viewname;
  • 更新视图时,可以先用DROP再用CREATE,也可以直接用CREAT OR REPLACE VIEW
  • 视图定义在创建时被“ 冻结 ”,并且不受基础表定义的后续更改的影响。
利用视图简化复杂的联结
mysql> CREATE VIEW productcustomers AS
    -> SELECT cust_name, cust_contact, prod_id
    -> FROM customers, orders, orderitems
    -> WHERE customers.cust_id = orders.cust_id
    ->   AND orderitems.order_num = orders.order_num;

这条语句创建一个名为productcustomers的视图,它联结了三个表,以返回已订购了任意产品的所有客户的列表。此时再检索订购了TNT2的客户,将非常简单:

mysql> SELECT cust_name, cust_contact
    -> FROM productcustomers
    -> WHERE prod_id = 'TNT2';
+----------------+--------------+
| cust_name      | cust_contact |
+----------------+--------------+
| Coyote Inc.    | Y Lee        |
| Yosemite Place | Y Sam        |
+----------------+--------------+
用视图重新格式化检索出的数据

视图可以重新格式化检索出的数据,避免了每次检索时需要拼接字段和联结表:

mysql> CREATE VIEW vendorlocations AS
    -> SELECT Concat(RTrim(vend_name),'(',RTrim(vend_country),')')
    ->        AS vend_title
    -> FROM vendors
    -> ORDER BY vend_name;
    
mysql> SELECT * FROM vendorlocations;
+------------------------+
| vend_title             |
+------------------------+
| ACME(USA)              |
| Anvils R Us(USA)       |
| Furball Inc.(USA)      |
| Jet Set(England)       |
| Jouets Et Ours(France) |
| LT Supplies(USA)       |
+------------------------+
用视图过滤不想要的数据

视图应用于简单的WHERE语句,可以为需要的数据创建视图

使用视图与计算字段

同格式化检索的数据相同

更新视图

通常,视图是可更新的(即可以对它们使用INSERT、UPDATE和DELETE)。更新视图将更新其基表。如果对视图增删行,实际是对其基表增删。
如果视图定义有一下操作,则不能进行视图更新:

  • 分组(使用GROUP BY和HAVING)
  • 联结
  • 子查询
  • 聚集函数(Min()、Count()、Sum()等)
  • DISTINCT
  • 导出(计算)列

听上去是个挺严重的限制,实际不是,因为视图主要用于数据检索。

存储过程

存储过程简单来说,为以后的使用而保存的一条或多条MySQL语句的集合。
存储的例程可以使过程,也可以是函数。使用CREATE PROCEDURECREATE FUNCTION语句创建存储的例程。
可将其视为批文件,虽然它们的作用不仅限于批处理。
存储过程三个主要的好处:简单、安全、高性能。

执行存储过程

MySQL称存储过程的执行为调用,语句为CALL。CALL接受存储过程的名字和需要传递给它的任意参数。

定义存储过程

每个存储程序都包含一个由SQL语句组成的主体。该语句可以是由多个用分号(;)字符分隔的语句组成的复合语句。例如,以下存储过程的主体由一个BEGIN … END包含一个SET 语句的块 和一个REPEAT本身包含另一个SET 语句的循环组成 :

mysql> CREATE PROCEDURE dorepeat(p1 INT)
    -> BEGIN
    ->   SET @x = 0;
    ->   REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
    -> END

如果使用mysql客户端程序定义包含分号字符的存储程序,则会出现问题。默认情况下,mysql本身将分号识别为语句定界符,因此必须临时重新定义定界符,以使mysql将整个存储的程序定义传递给服务器。

要重新定义mysql分隔符,使用 delimiter命令。以下示例显示了如何针对dorepeat()刚刚显示的过程执行此操作。分隔符已更改为//允许将整个定义作为单个语句传递到服务器,然后;在调用该过程之前还原到。这使; 过程主体中使用的定界符可以传递到服务器,而不是由mysql 本身解释。

mysql> delimiter //
# 所有MySQL变量都必须以@开始
mysql> CREATE PROCEDURE dorepeat(p1 INT)
    -> BEGIN
    ->   SET @x = 0;
    ->   REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
    -> END
    -> //
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

mysql> CALL dorepeat(1000);
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @x;
+------+
| @x   |
+------+
| 1001 |
+------+
1 row in set (0.00 sec)

可以将定界符重新定义为以外的其他字符串 //,并且定界符可以包含一个或多个字符。但应该避免使用反斜杠(\)字符,因为这是MySQL的转义字符。

下面是一个函数示例,该函数采用参数,使用SQL函数执行操作,然后返回结果。在这种情况下,delimiter由于函数定义不包含内部;语句定界符,因此无需使用 :

mysql> CREATE FUNCTION hello (s CHAR(20))
mysql> RETURNS CHAR(50) DETERMINISTIC
    -> RETURN CONCAT('Hello, ',s,'!');
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT hello('world');
+----------------+
| hello('world') |
+----------------+
| Hello, world!  |
+----------------+
1 row in set (0.00 sec)
删除存储过程

存储过程在创建之后,被保存在服务器上以供使用,直至被删除。

DROP PROCEDURE dorepeat;
DROP FUNCTION hello;
建立智能存储过程

存储过程内包含业务规则和智能处理时,它们的威力才真正显现出来。
考虑这样一个场景。需要获得一个订单合计,并针对某些顾客增加营业税:

  1. 获得合计
  2. 把营业税有条件地添加到合计
  3. 返回合计(带或不带税)

存储过程的完整工作如下:

CREATE PROCEDURE ordertotal(
   IN onumber INT,
   IN taxable BOOLEAN,
   OUT ototal DECIMAL(8,2)
 ) COMMENT 'Obain order total, optionally adding tax'
BEGIN
    -- Declare variable for total
    DECLARE total DECIMAL(8,2);
    -- Declare tax percentage
    DECLARE taxrate INT DEFAULT 6;

    -- Get the order total
    SELECT Sum(item_price*quantity)
    FROM orderitems
    WHERE order_num = onumber
    INTO total;

    -- Is this taxable?
    IF taxable THEN
        -- Yes, so add taxrate to the total
        SELECT total+(total/100*taxrate) INTO total;
    END IF;

    -- And finally, save to out variable
    SELECT total INTO ototal;

END;

这个存储过程稍显复杂:

  • 增加了注释“-- ”
  • 用DECLARE语句定义了两个局部变量,要求指定变量名和数据类型,也支持可选的默认值
  • 用SELECT INTO 将查询结果保存到变量
  • COMMENT关键字不是必需的,如果给出,将在SHOW PROCEDURE STATUS的结果中显示

为了试验它,用下面两条语句:

mysql> CALL ordertotal(20005, 0, @total);
Query OK, 1 row affected (0.01 sec)

mysql> SELECT @total;
+--------+
| @total |
+--------+
| 149.87 |
+--------+
1 row in set (0.00 sec)

mysql> CALL ordertotal(20005, 1, @total);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT @total;
+--------+
| @total |
+--------+
| 158.86 |
+--------+
1 row in set (0.00 sec)
检查存储过程

为了实现用来创建一个存储过程的CREATE语句,使用SHOW CREATE PROCEDURE语句;
为了获得包括何时,由谁创建等详细信息的存储过程列表,使用SHOW PROCEDURE STATUS语句(会列出所有存储过程,为限制输出,可使用LIKE指定一个过滤模式):

mysql> SHOW PROCEDURE STATUS LIKE 'ordertotal';
+------+------------+-----------+----------------+---------------------+---------------------+---------------+------------------------------------------+----------------------+----------------------+--------------------+
| Db   | Name       | Type      | Definer        | Modified            | Created             | Security_type | Comment                                  | character_set_client | collation_connection | Database Collation |
+------+------------+-----------+----------------+---------------------+---------------------+---------------+------------------------------------------+----------------------+----------------------+--------------------+
| shop | ordertotal | PROCEDURE | root@localhost | 2020-04-05 16:10:03 | 2020-04-05 16:10:03 | DEFINER       | Obain order total, optionally adding tax | gbk                  | gbk_chinese_ci       | utf8mb4_0900_ai_ci |
+------+------------+-----------+----------------+---------------------+---------------------+---------------+------------------------------------------+----------------------+----------------------+--------------------+
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值