SQL基本语句(以MySQL为例)-- 第五部分

19、使用存储过程
MySQL的存储过程的语句跟这本书上的差太远了吧,以下参考自:MySQL存储过程教程

DELIMITER //  -- 先把分隔符“;”换成“//”,以免非预期的语句结束
CREATE PROCEDURE mailing_list_count(
    OUT list_count INT
    -- OUT表示该参数用来返回值
    -- IN表示用来传递值
    -- INOUT更多查看上面的参考
)
BEGIN
    DECLARE v_rows INT;
    SELECT COUNT(*) INTO v_rows
    FROM customers
    WHERE NOT cust_email IS NULL;
    SET list_count = v_rows;
END//  -- 这里才是这整个CREATE PROCEDURE语句的结束
DELIMITER ;  -- 恢复分隔符为“;”,注意有个空格
CALL mailing_list_count(@count);  -- 调用存储过程
SELECT @count;  --查看count的值

20、管理事务处理
事务处理用来确保一连串相关的表操作,能够全部执行完毕,如果其中某步骤出错,则进行回滚。
比如1个新顾客,下了1个订单,其中有2个商品,将涉及到3个表的操作。
可以撤销的操作:INSERT、UPDATE、DELETE,不能撤销的操作:SELECT、CREATE、DROP。
嗯,,,这个书上的例子,完全不能用在MySQL中

BEGIN;  -- 或者START TRANSACTION;
DELETE FROM orders WHERE order_num = 343242;
COMMIT;  -- 在执行COMMIT前,都可以用ROLLBACK撤销之前的所有操作
-- 带保留点的回滚
BEGIN;
DELETE FROM orders WHERE order_num = 123;
SAVEPOINT delete1;
DELETE FROM orders WHERE order_num = 1212;
DELETE FROM orders WHERE order_num = 231;
ROLLBACK TO delete1;  -- 只撤销SAVEPOINT delete1这句(保留点)之后的语句

21、使用游标
这里由于书上的例子完全不太适用于MySQL,所以参考:《MySQL必知必会》
首先MySQL中的游标只能在存储过程中,然后是只读,只能往一个方向移动,不能跳行

先定义另一个要用到的存储过程

DELIMITER //
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//
DELIMITER ;

循环使用游标,如果不用循环的话,相当于只读取了第一行

DELIMITER //
CREATE PROCEDURE ProcessOrders()
BEGIN
    -- 定义局部变量
    DECLARE done BOOLEAN DEFAULT 0;
    DECLARE o INT;
    DECLARE t DECIMAL(8, 2);

    -- 定义游标
    DECLARE OrderNumbers CURSOR
    FOR
    SELECT order_num FROM orders;

    -- 定义CONTINUE HANDLER
    -- SQLSTATE '02000'是一个未找到条件,当REPEAT由于没有更多的行供循环而不能继续时,出现这个条件。
    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, t);  -- 调用前面的存储过程,返回总价,存储在变量t中
        INSERT INTO ordertotals(order_num, total)
        VALUES(o, t);
    UNTIL done END REPEAT;
    CLOSE OrderNumbers;
END//
DELIMITER ;

调用存储过程,会在表ordertotals(如果不存在,则先创建)中插入,每个订单的总价值

CALL ProcessOrders();
SELECT * FROM ordertotals;
-- 输出,这里为什么会有2个20008?没搞清楚,,
+-----------+---------+
| order_num | total   |
+-----------+---------+
|     20005 | 1648.00 |
|     20009 | 1867.50 |
|     20006 |  329.60 |
|     20007 | 1696.00 |
|     20008 |  189.60 |
|     20008 |  189.60 |
+-----------+---------+

《SQL必知必会》最后一章就直接过目一下了,之后再来扫一遍《MySQL必知必会》当作加深记忆,因为现在根本用不到,所以就多看一遍,不然很快就忘了

参考:SQL必知必会(第四版)
参考:MySQL必知必会

你可能感兴趣的:(SQL基本语句(以MySQL为例)-- 第五部分)