• MySQL存储过程


    1.参数验证和错误反馈
    mysql 5.5开始引入SIGNAL语句,通过它可以反馈存储过程的数据验证错误.在5.5之前的版本,只能通过其它方法变通解决.
    SIGNAL语句的语法:
    SIGNAL SQLSTATE [value] sqlstate_value

    [SET MESSAGE_TEXT = message[,mysql_ERRNO = mysql_error_number]];

    例子:

    USE ap;
    
    DROP PROCEDURE IF EXISTS insert_invoice;
    
    DELIMITER //
    
    CREATE PROCEDURE insert_invoice
    (
      vendor_id_param        INT,
      invoice_number_param   VARCHAR(50),
      invoice_date_param     DATE,
      invoice_total_param    DECIMAL(9,2),
      terms_id_param         INT,
      invoice_due_date_param DATE
    )
    BEGIN
      DECLARE terms_id_var           INT;
      DECLARE invoice_due_date_var   DATE;  
      DECLARE terms_due_days_var     INT;
    
      -- Validate paramater values
      IF invoice_total_param < 0 THEN     SIGNAL SQLSTATE '22003'       SET MESSAGE_TEXT = 'The invoice_total column must be a positive number.',        MYSQL_ERRNO = 1264;   ELSEIF invoice_total_param >= 1000000 THEN
        SIGNAL SQLSTATE '22003'
          SET MESSAGE_TEXT = 'The invoice_total column must be less than 1,000,000.', 
          MYSQL_ERRNO = 1264;
      END IF;
    
      -- Set default values for parameters
      IF terms_id_param IS NULL THEN
        SELECT default_terms_id INTO terms_id_var
        FROM vendors WHERE vendor_id = vendor_id_param;
      ELSE
        SET terms_id_var = terms_id_param;
      END IF;
      IF invoice_due_date_param IS NULL THEN
        SELECT terms_due_days INTO terms_due_days_var
          FROM terms WHERE terms_id = terms_id_var;
        SELECT DATE_ADD(invoice_date_param, INTERVAL terms_due_days_var DAY) 
          INTO invoice_due_date_var;
      ELSE
        SET invoice_due_date_var = invoice_due_date_param;
      END IF;
    
      INSERT INTO invoices
             (vendor_id, invoice_number, invoice_date, 
              invoice_total, terms_id, invoice_due_date)
      VALUES (vendor_id_param, invoice_number_param, invoice_date_param, 
              invoice_total_param, terms_id_var, invoice_due_date_var);
    END//
    
    DELIMITER ;
    
    -- test
    CALL insert_invoice(34, 'ZXA-080', '2012-01-18', 14092.59, 
                        3, '2012-03-18');
    CALL insert_invoice(34, 'ZXA-082', '2012-01-18', 14092.59,
                        NULL, NULL);
    
    -- this statement raises an error
    CALL insert_invoice(34, 'ZXA-083', '2012-01-18', -14092.59,
                        NULL, NULL);
    
    -- clean up
    SELECT * FROM invoices WHERE invoice_id >= 115;
    
    DELETE FROM invoices WHERE invoice_id >= 115;

    2.使用动态SQL
    通过PREPARE,EXECUTE,DEALLOCATE等语句可以在存储过程中创建动态SQL.

    例子:

    USE ap;
    
    DROP PROCEDURE IF EXISTS select_invoices;
    
    DELIMITER //
    
    CREATE PROCEDURE select_invoices
    (
      min_invoice_date_param   DATE,
      min_invoice_total_param  DECIMAL(9,2)
    )
    BEGIN
      DECLARE select_clause VARCHAR(200);
      DECLARE where_clause  VARCHAR(200);
    
      SET select_clause = "SELECT invoice_id, invoice_number, 
                           invoice_date, invoice_total 
                           FROM invoices ";      
      SET where_clause =  "WHERE ";
    
      IF min_invoice_date_param IS NOT NULL THEN
        SET where_clause = CONCAT(where_clause, 
           " invoice_date > '", min_invoice_date_param, "'");
      END IF;
    
      IF min_invoice_total_param IS NOT NULL THEN
        IF where_clause != "WHERE " THEN
          SET where_clause = CONCAT(where_clause, "AND ");
        END IF;
        SET where_clause = CONCAT(where_clause, 
           "invoice_total > ", min_invoice_total_param);
      END IF;
    
      IF where_clause = "WHERE " THEN
        SET @dynamic_sql = select_clause;
      ELSE
        SET @dynamic_sql = CONCAT(select_clause, where_clause);    
      END IF;
    
      PREPARE select_invoices_statement
      FROM @dynamic_sql;
    
      EXECUTE select_invoices_statement;
    
      DEALLOCATE PREPARE select_invoices_statement;  
    END//
    
    DELIMITER ;
    
    CALL select_invoices('2011-07-25', 100);
    
    CALL select_invoices('2011-07-25', NULL);
    
    CALL select_invoices(NULL, 1000);
    
    CALL select_invoices(NULL, NULL);

    3.使用游标

    游标定义:
    DECLARE cursor_name CURSOR FOR select_statement;
    游标错误控制:
    DECLARE CONTINUE HANDLER FOR NOT FOUND handler_statement;
    打开游标:
    OPEN cursor_name;
    获取游标行的值并保存到一系列变量中:
    FETCH cursor_name INTO variable1[, variable2][, variable3]…;
    关闭游标:
    CLOSE cursor_name;

    例子:

    USE ap;
    
    DROP PROCEDURE IF EXISTS test;
    
    DELIMITER //
    
    CREATE PROCEDURE test()
    BEGIN
      DECLARE invoice_id_var    INT;
      DECLARE invoice_total_var DECIMAL(9,2);  
      DECLARE row_not_found     TINYINT DEFAULT FALSE;
      DECLARE update_count      INT DEFAULT 0;
    
      DECLARE invoices_cursor CURSOR FOR
        SELECT invoice_id, invoice_total  FROM invoices
        WHERE invoice_total - payment_total - credit_total > 0;
    
      DECLARE CONTINUE HANDLER FOR NOT FOUND
        SET row_not_found = TRUE;
    
      OPEN invoices_cursor;
    
      WHILE row_not_found = FALSE DO
        FETCH invoices_cursor INTO invoice_id_var, invoice_total_var;
    
        IF invoice_total_var > 1000 THEN
          UPDATE invoices
          SET credit_total = credit_total + (invoice_total * .1)
          WHERE invoice_id = invoice_id_var;
    
          SET update_count = update_count + 1;
        END IF;
      END WHILE;
    
      CLOSE invoices_cursor;
    
      SELECT CONCAT(update_count, ' row(s) updated.');
    
    END//
    
    DELIMITER ;
    
    CALL test();

    4.事务控制

    先定义一个sql_error标识,然后对SQLEXCEPTION进行捕捉,最后根据sql_error标识来控制事务的commit或rollback.

    看例子:

    USE ap;
    
    DROP PROCEDURE IF EXISTS test;
    
    DELIMITER //
    
    CREATE PROCEDURE test()
    BEGIN
      DECLARE sql_error INT DEFAULT FALSE;
      
      DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
        SET sql_error = TRUE;
    
      START TRANSACTION;
      
      INSERT INTO invoices
      VALUES (115, 34, 'ZXA-080', '2011-06-30', 
              14092.59, 0, 0, 3, '2011-09-30', NULL);
    
      INSERT INTO invoice_line_items 
      VALUES (115, 1, 160, 4447.23, 'HW upgrade');
      
      INSERT INTO invoice_line_items 
      VALUES (115, 2, 167, 9645.36, 'OS upgrade');
      
      IF sql_error = FALSE THEN
        COMMIT;
        SELECT 'The transaction was committed.';
      ELSE
        ROLLBACK;
        SELECT 'The transaction was rolled back.';
      END IF;
    END//
    
    DELIMITER ;
    
    CALL test();
    
    -- Check data
    SELECT invoice_id, invoice_number
    FROM invoices WHERE invoice_id = 115;
    
    SELECT invoice_id, invoice_sequence, line_item_description
    FROM invoice_line_items WHERE invoice_id = 115;
    
    -- Clean up
    DELETE FROM invoice_line_items WHERE invoice_id = 115;
    DELETE FROM invoices WHERE invoice_id = 115;
  • 相关阅读:
    callable函数,检查对象是否可调用
    eval函数的一些用法
    divmod函数使用
    sorted(x, reverse=True)
    列表、元组、字典空格的几种移除方法
    约瑟夫环问题(通过观察得出递推式从而建立递归求解)
    快速幂算法(二分思想减少连乘次数)
    素数筛(埃氏筛法与欧拉筛)
    KMP算法的详细解释
    对于线性代数的形象化理解(1)
  • 原文地址:https://www.cnblogs.com/zeroone/p/4256516.html
Copyright © 2020-2023  润新知