注:博客中总结《MySQL必知必会》中的知识点,第22,23,24,25章的核心内容;
涉及到的操作符:VIEW,PROCEDURE,CALL,DECLARE,IF,REPEAT,END,FETCH,TRIGGER;
书中用到的表的介绍及其脚本文件:《Mysql必知必会》中表的介绍
视图是虚拟的表(我的理解就是想C++中的引用),它的好处有:
- 重用SQL语句;
- 简化复杂的SQL操作;
- 使用表的组成部分而不是整个表;
- 保护数据
- 更改数据格式和表示;
CREARE 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;
-- 这样以后检索订购TNT2的客户,可如下进行:
SELECT cust_name, cust_contact
FROM productcutomers
WHERE prod_id = 'TNT2';
CREATE VIEW vendorlocations AS
SLECT Concat(RTrim(vend_name),'(',RTrim(vend_country),')')
AS vend_title
FROM vendors
ORDER BY vend_name;
-- 直接检索即可
SELECT *
FROM vendorlocations;
CREATE VIEW customermaillist AS
SELECT cust_id, cust_name, cust_email
FROM customers
WHERE cust_email IS NOT NULL;
-- 直接检索即可
SELECT *
FROM customermaillist;
CREATE VIEW customermaillist AS
SELECT cust_id, cust_name, cust_email
FROM customers
WHERE cust_email IS NOT NULL;
-- 直接检索即可
SELECT *
FROM customermaillist;
CREATE VIEW orderitemsexpended AS
SELECT prod_id,
quantity,
item_price,
quantity*item_price AS expanded_price
FROM orderitems;
-- 直接检索即可
SELECT *
FROM orderitemsexpanded
WHERE order_num = 20005;
如果视图定义有一下操作,则不能进行视图的更新;
- 分组
- 联结
- 子查询
- 并
- 聚集函数
类似于函数;
存储过程的3个主要好处,即简单,安全和高性能;
-- 使用PROCEDURE定义存储过程;
CREATE PROCEDURE productpricing()
BEGIN
SELECT AVG(prod_price) AS priceaverage
FROM products;
END;
-- 使用CALL调用存储过程;
CALL productpricing();
DROP PROCEDURE productpricing;
-- 使用PROCEDURE定义只带输出参数的存储过程;
CREATE PROCEDURE productpricing(
OUT pl DECIMAL(8,2),
OUT ph DECIMAL(8,2),
OUT pa DECIMAL(8,2)
)
BEGIN
SELECT Min(prod_price)
INTO pl
FROM products;
SELECT Max(prod_price)
INTO ph
FROM products;
SELECT AVG(prod_price)
INTO pa
FROM products;
END;
-- 使用CALL调用存储过程;
CALL productpricing(@pricelow,
@pricehigh,
@priceaverage);
-- 显示检索出的产品最低,最高,平均价格
SELECT @pricehigh,@pricelow,@priceaverage;
-- 使用PROCEDURE定义带输入,输出参数的存储过程;
CREATE PROCEDURE ordertotal(
IN onumber INT,
OUT ototal DECIMAL(8,2)
)
BEGIN
SELECT Sum(item_price*quantity)
FROM orderitems
WHERE order_num = onumber
INTO ototal;
END;
-- 使用CALL调用存储过程;
CALL ordertotal(20005, @total);
-- 显示检索出的产品最低,最高,平均价格
SELECT @total;
-- 这样还可以方便的得到另一个订单的合计过程
CALL ordertotal(20009,@total);
SELECT @total;
增加 IF 判断
-- 定义智能存储过程
CREATE PROCEDURE ordertotal(
IN onumber INT,
IN taxable BOOLEN,
OUT otatol DECIMAL(8,2)
)
BEGIN
-- 声明变量
DECLARE total DECIMAL(8,2);
DECLARE taxrate INT DEFAULT 6;
-- 得到全部订单
SELECT Sum(item_price*quantity)
FROM orderitems
WHERE order_num=onumber
INTO total;
-- IF 判断
IF taxable THEN
SELECT total+(total/100*taxarate) INTO total;
END IF;
SELECT total INTO ototal;
END;
CALL ordertotal(20005,0,@tatol);
SELECT #total;
CALL ordertotal(20005,1,@tatol);
SELECT #total;
-- 显示创建存储过程的CREATE语句;
SHOW CREATE PROCEDURE ordertotal;
游标只能用于存储过程;
游标的作用:在检索出来的行中可以前进或者后退一行或多行;(类似于指针?)
CREATE PROCEDURE processorders()
BEGIN
DECLARE ordernumbers CURSOR -- 声明游标
FOR
SELECT order_num FROM orders;
END;
-- 打开游标
OPEN ordernumbers;
-- 关闭游标
CLOSE ordernumbers;
CREATE PROCEDURE processorders()
BEGIN
-- 声明局部变量
DECLARE done BOOLEN DEFAULT 0;
DECLARE o INT;
DECLARE t DECIMAL(8,2);
-- 声明游标
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM order;
-- 定义是否终止的条件
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
-- 创建表
CREATE TABLE IF NOT EXISTS ordertotals
(order_num INT, total DECIMAL(8,2));
-- 打开游标
OPEN ordernumbers;
-- 进入循环
REPEAT
FETCH ordernumbers INTO o; -- 得到游标具体的值
CALL ordertotal(o, 1 ,t); -- 调用存储过程
INSERT INTO ordertotals(order_num, total) -- 插入到新建的表中
VALUES(o, t);
UNTIL done END REPEAT;
-- 关闭游标
CLOSE ordernumbers;
END
-- 检索新建的表
CALL processorders();
SELECT * FROM ordertotals;
触发器的作用:需要某条语句在事件发生时自动执行
只有表支持触发器,视图不支持。在创建触发器时,需要给出四条信息:
- 唯一的触发器名;
- 触发器关联的表;
- 触发器应该响应的活动(DELETE,INSERT或UPDATE)
- 触发器何时执行(处理之前或之后);
CREATE TRIGGER newproduct AFTER INSERT ON PRODUCTS
FOR EACH ROW SELECT 'Product added';
-- 创建了一个newproduct新触发器。在INSERT语句成功执行之后执行,并对每个插入行执行。在这个例子中,文本‘Product added’在每个插入的行显示一次;
DROP TRIGGER newproduct;
-- 定义INSERT触发器
CREATE TRIGGER neworder AFTEr INSERT ON orders
FOR EACH ROW SELECT NEW.order_num;
-- 测试触发器
INSERT INTO orders(order_date, cust_id)
VAlUES(Now(), 10001);
-- 定义DELETE触发器,在DELETE语句中可以引用一个OLD的只读虚拟表。可以访问被删除的行;
CREATE TRIGGER deleteorder BEFORE DELETE ON orders
FOR EACH ROW
BEGIN
INSERT INTO archive_orders(order_num, order_date, cust_id)
VALUES(OLD.order_num, OLD.order_date, OLD.cust_id);
END;
-- 在任意订单被删除之前执行此触发器。见删除之保存删除行;
-- 定义DELETE触发器,在UPDATE语句中可以引用一个OLD的只读虚拟表访问以前的值。
-- 还会引用一个NEW的虚拟表访问新更新的值;
CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors
FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state);
-- 任何数据净化都需要在UPDATE语句之前进行,每次更新一行时,都会通过Upper();