RUNOOB

  1. -- 将语句的结束符号从分号;临时改为两个$$(可以是自定义)
  2. mysql> delimiter $$
  3. -- 如果想指定存储过程创建在某个特定的数据库下,那么在过程名前面加数据库名做前缀。
  4. mysql > DELIMITER //
  5. mysql > CREATE PROCEDURE proc1
  6. -> (IN parameter1 INTEGER)
  7. -> BEGIN
  8. -> DECLARE variable1 CHAR(10);
  9. -> IF parameter1 = 17 THEN
  10. -> SET variable1 = 'birds';
  11. -> ELSE
  12. -> SET variable1 = 'beasts';
  13. -> END IF;
  14. -> INSERT INTO table1 VALUES (variable1);
  15. -> END
  16. -> //
  17. -- 将语句的结束符号恢复为分号
  18. mysql > DELIMITER;
  19. mysql > call proc1(18);
  1. -- 没有BEGINEND
  2. mysql > CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World');
  3. mysql > SET @greeting='Hello';
  4. mysql > CALL GreetWorld( );

存储过程体

存储过程体包含了在过程调用时必须执行的语句,例如:dml、ddl语句,if-then-else和while-do语句、声明变量的declare语句

  1. label1: BEGIN
  2.   label2: BEGIN
  3.     label3: BEGIN
  4.       statements;
  5.     END label3 ;
  6.   END label2;
  7. END label1

存储过程的参数

CREATE PROCEDURE 存储过程名([[IN |OUT |INOUT ] 参数名 数据类型…])

变量

变量定义

放在存储过程体的开始

  1. DECLARE l_int int unsigned default 4000000;
  2. DECLARE l_numeric number(8,2) DEFAULT 9.95;
  3. DECLARE l_date date DEFAULT '1999-12-31';

变量赋值

  1. -- 存储过程体中
  2. set p_in=2;
  3. -- 用户变量名一般以@开头
  4. set @greeting='Hello'
  5. -- 读取
  6. SELECT @greeting;

MySQL存储过程的查询、修改、删除

见参考链接。

MySQL存储过程的控制语句

见参考链接。

为什么阿里巴巴禁止使用存储过程?

Mosh

image.png

多个参数、IFNULL、参数验证抛出错误

  1. USE sql_invoice;
  2. DROP PROCEDURE IF EXISTS get_payments;
  3. DELIMITER $$
  4. CREATE PROCEDURE get_payments
  5. (
  6. client_id INT(4),
  7. payment_method_id TINYINT(2)
  8. )
  9. BEGIN
  10. IF client_id <= 0 OR payment_method_id <= 0 THEN
  11. SIGNAL SQLSTATE '22023'
  12. SET MESSAGE_TEXT = 'Invalid client_id or payment_method_id';
  13. END IF;
  14. SELECT * FROM payments p
  15. where p.client_id = IFNULL(client_id, p.client_id)
  16. and p.payment_method = IFNULL(payment_method_id, p.payment_method);
  17. END$$
  18. DELIMITER ;
  19. CALL get_payments(NULL, NULL);
  20. CALL get_payments(3, NULL);
  21. CALL get_payments(NULL, 2);
  22. CALL get_payments(3, 1);
  23. CALL get_payments(-1, -1);

验证原则:最少、应用优先、数据库兜底

因为付款总计列本就不允许空值,所以如果你给这个过程传递了空值,MYSQL会自动标注这一错误,所以尽量利用最少的验证逻辑,只保留最最关键的那些。相比访问数据库,在应用中检测和报告错误会更快速,把参数验证作为终极备选方案,以防有人在没有通过应用直接调用了你的存储过程的情况。

-输出参数,DECIMAL数据类型

尽量避免输出参数

  1. DROP PROCEDURE IF EXISTS sql_invoice.get_unpaid_invoices_for_client;
  2. DELIMITER $$
  3. $$
  4. CREATE PROCEDURE sql_invoice.get_unpaid_invoices_for_client(
  5. client_id INT,
  6. OUT invoice_count INT,
  7. OUT invoice_total DECIMAL(9,2)
  8. )
  9. BEGIN
  10. SELECT COUNT(*), SUM(i.invoice_total)
  11. INTO invoice_count, invoice_total
  12. FROM invoices i
  13. WHERE i.client_id = client_id
  14. AND i.payment_total = 0;
  15. END
  16. $$
  17. DELIMITER ;