文章目录

  • MySQL 存储过程面试基础知识总结
    • 一、存储过程基础
      • (一)概述
        • 1.优点
        • 2.缺点
      • (二)创建与调用
        • 1.创建存储过程
        • 2.调用存储过程
        • 3.查看存储过程
        • 4.修改存储过程
        • 5.存储过程权限管理
      • (三)参数
        • 1.输入参数
        • 2.输出参数
        • 3.输入输出参数
      • (四)控制流语句
        • 1.IF - ELSE 语句
        • 2.WHILE 循环语句
        • 3.CASE 语句
        • 4.LOOP 循环
        • 5.REPEAT 循环
      • (五)练习
        • 练习一:创建和调用存储过程
        • 练习二:使用输出参数
        • 练习三:控制流语句应用
    • 二、变量
      • (一)局部变量
        • 1.定义
        • 2.声明
        • 3.赋值
        • 4.作用域
      • (二)全局变量
        • 1.定义
        • 2.声明
        • 3.赋值
        • 4.作用域
      • (三)示例
        • 1.局部变量示例
        • 2.全局变量示例
      • (四)面试常问问题
        • 1.局部变量和全局变量的区别是什么?
        • 2.如何声明和使用局部变量?
        • 3.如何查看和设置全局变量的值?
        • 4.在存储过程中如何使用局部变量?
        • 5.全局变量和局部变量的命名冲突如何解决?
      • 附:【局部变量 用户定义的变量(带@的变量) 全局变量 】三者对比
        • 示例代码
        • 详细解释
    • 三、 游标(CURSOR)
      • 定义
      • 声明
      • 打开游标
      • 获取数据
      • 关闭游标
      • 示例
    • 四、处理程序(HANDLER)
      • 定义
      • 声明
      • 示例
    • 五、 事务控制
      • 事务概述
      • BEGIN、COMMIT、ROLLBACK 语句
      • 示例
    • 六、 动态 SQL
      • 动态 SQL 概述
      • PREPARE、EXECUTE、DEALLOCATE PREPARE 语句
      • 示例
    • 八、 存储过程案例:
      • 批量数据处理示例:批量更新用户积分
      • 数据校验示例:校验用户输入数据
      • 复杂业务逻辑封装示例:计算订单总金额


MySQL 存储过程面试基础知识总结

一、存储过程基础

存储过程(Stored Procedure)是一组 SQL 语句的集合,存储在数据库中,通过指定名称和参数调用执行。它主要用于提高性能、代码复用和增强安全性。

(一)概述

1.优点
  • 提高性能:存储过程在数据库服务器端执行,减少了网络传输的次数。例如,当需要对大量数据进行复杂的查询和更新操作时,存储过程可以将这些操作封装在一起,一次执行完成,大大减少了网络通信开销。而且存储过程在第一次执行时会被编译,之后的调用可以直接执行编译后的代码,提高了执行效率。
  • 代码复用:可以将常用的 SQL 操作封装成存储过程,方便在不同的应用程序和地方调用。比如,一个企业数据库中,经常需要查询员工的详细信息,包括姓名、部门、工资等,将这些查询操作封装成存储过程后,不同的部门在开发自己的应用程序时就可以直接调用这个存储过程来获取数据,避免重复编写代码。
  • 安全性增强:可以通过存储过程控制用户对数据库的访问权限。例如,只允许用户通过特定的存储过程来修改数据,而不能直接对表进行修改操作,这样可以防止用户对数据库进行不恰当的操作,提高数据库的安全性。
2.缺点
  • 可移植性差:不同数据库管理系统(DBMS)的存储过程语法有所不同。例如,SQL Server 使用 Transact - SQL(T - SQL)语言来编写存储过程,而 MySQL 使用自己的存储过程语法。如果要将一个数据库从 SQL Server 迁移到 MySQL,存储过程可能需要重新编写或修改。
  • 调试困难:存储过程的调试相对复杂,特别是在存储过程比较复杂,包含多个分支和循环时。与在应用程序代码中调试相比,数据库端的调试工具通常没有那么强大,很难像在高级语言(如 Java、Python)中那样方便地设置断点、查看变量值等。

(二)创建与调用

1.创建存储过程

在 MySQL 中,创建存储过程的基本语法如下:

DELIMITER $$CREATE PROCEDURE procedure_name( [ IN | OUT | INOUT ] parameter_name parameter_data_type, ... )
BEGIN-- SQL statements
END$$DELIMITER ;
  • DELIMITER:MySQL 默认的语句分隔符是分号(;)。在存储过程内部,可能会包含多个 SQL 语句,这些语句也需要用分号分隔。为了避免与存储过程内部的分号冲突,需要将分隔符改为其他字符(如 $$)。在存储过程定义完成后,再将分隔符改回默认的分号。
  • IN、OUT、INOUT:用于指定参数的类型。IN 表示输入参数,OUT 表示输出参数,INOUT 表示输入输出参数。
  • parameter_name 和 parameter_data_type:分别是参数的名称和数据类型。例如,IN employee_id INT 表示一个名为 employee_id 的输入参数,数据类型为整数。
  • SQL statements:是存储过程要执行的 SQL 语句,可以是查询、插入、更新、删除等操作。

例如,创建一个存储过程,用于查询员工的工资信息:

DELIMITER $$CREATE PROCEDURE GetEmployeeSalary(IN employee_id INT)
BEGINSELECT salaryFROM employeesWHERE employee_id = employee_id;
END$$DELIMITER ;
2.调用存储过程

调用存储过程的语法为:

CALL procedure_name(parameter1, parameter2, ...);

对于上面创建的 GetEmployeeSalary 存储过程,调用它来查询员工编号为 1001 的员工工资:

CALL GetEmployeeSalary(1001);
3.查看存储过程

查看某个数据库下面的存储过程:

select name from mysql.proc where db='数据库名';或者select routine_name from information_schema.routines where routine_schema='数据库名';或者show procedure status where db='数据库名';

在 MySQL 8.0 及更高版本中,存储过程和函数的元数据存储在 INFORMATION_SCHEMA.ROUTINES 表中,而不是 mysql.proc 表中。
在这里插入图片描述

在这里插入图片描述

详细查看存储过程:
1.SHOW CREATE PROCEDURE 语句

SHOW CREATE PROCEDURE procedure_name;

在这里插入图片描述

2.INFORMATION_SCHEMA 表

SELECT * FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_NAME = 'procedure_name';

在这里插入图片描述

4.修改存储过程

删除并重新创建

DROP PROCEDURE procedure_name;
CREATE PROCEDURE procedure_name ...

使用 ALTER PROCEDURE 语句(MySQL 8.0+)

ALTER PROCEDURE procedure_name ...
5.存储过程权限管理

授予权限

GRANT EXECUTE ON procedure_name TO 'username'@'host';

撤销权限

REVOKE EXECUTE ON procedure_name FROM 'username'@'host';

(三)参数

1.输入参数

输入参数是调用存储过程时从外部传入的参数,存储过程内部根据这些参数来执行相应的操作。在前面的 GetEmployeeSalary 存储过程中,employee_id 就是一个输入参数。

2.输出参数

输出参数是存储过程执行完成后返回给调用者的参数。在 MySQL 中,输出参数需要在参数定义时加上 OUT 关键字。例如,创建一个存储过程,计算两个数的和,并将结果通过输出参数返回:

DELIMITER $$CREATE PROCEDURE AddTwoNumbers(IN number1 INT, IN number2 INT, OUT sum INT)
BEGINSET sum = number1 + number2;
END$$DELIMITER ;

调用这个存储过程并获取输出参数的值:

SET @result = 0;
CALL AddTwoNumbers(5, 3, @result);
SELECT @result AS Sum;
3.输入输出参数

输入输出参数既可以接收外部传入的值,也可以在存储过程执行完成后将修改后的值返回给调用者。在 MySQL 中,输入输出参数需要加上 INOUT 关键字。例如,创建一个存储过程,将输入的数字乘以 2,并将结果返回:

DELIMITER $$CREATE PROCEDURE DoubleNumber(INOUT number INT)
BEGINSET number = number * 2;
END$$DELIMITER ;

调用这个存储过程:

SET @input_number = 10;
CALL DoubleNumber(@input_number);
SELECT @input_number AS Result;

(四)控制流语句

1.IF - ELSE 语句

用于条件判断。例如,创建一个存储过程,根据员工的工资等级(通过输入参数传入)来判断是否发放奖金:

DELIMITER $$CREATE PROCEDURE CheckBonus(IN salary_grade INT)
BEGINIF salary_grade = 1 THENSELECT '发放奖金';ELSESELECT '不发放奖金';END IF;
END$$DELIMITER ;
2.WHILE 循环语句

用于循环操作。例如,创建一个存储过程,将表中的员工工资依次增加 100,直到工资超过 10000:

DELIMITER $$CREATE PROCEDURE IncreaseSalary()
BEGINDECLARE employee_id INT DEFAULT 1;DECLARE current_salary INT;WHILE TRUE DOSELECT salary INTO current_salaryFROM employeesWHERE employee_id = employee_id;IF current_salary IS NULL THENLEAVE;END IF;IF current_salary < 10000 THENUPDATE employeesSET salary = salary + 100WHERE employee_id = employee_id;END IF;SET employee_id = employee_id + 1;END WHILE;
END$$DELIMITER ;

非常抱歉遗漏了 CASE 语句的介绍。CASE 语句在 MySQL 中用于条件判断,类似于其他编程语言中的 switch 语句。它可以根据不同的条件执行不同的代码块。现在我将补充 CASE 语句的内容,并提供一个示例。

3.CASE 语句

CASE 语句用于根据不同的条件执行不同的代码块。它可以根据一个表达式的值选择执行多个分支中的一个。

CASE 语句的基本语法如下:

CASE case_valueWHEN when_value1 THEN statement1;WHEN when_value2 THEN statement2;...ELSE statementN;
END CASE;
  • case_value:要比较的表达式。
  • when_value:与 case_value 比较的值。
  • statement:当 case_value 等于 when_value 时执行的语句。
  • ELSE:可选,当 case_value 不等于任何 when_value 时执行的语句。

以下是一个使用 CASE 语句的存储过程示例,根据员工的工资等级(通过输入参数传入)来判断是否发放奖金,并打印相应的消息:

DELIMITER $$CREATE PROCEDURE CheckBonus(IN salary_grade INT)
BEGINCASE salary_gradeWHEN 1 THENSELECT '发放奖金';WHEN 2 THENSELECT '发放小礼品';WHEN 3 THENSELECT '发放感谢信';ELSESELECT '不发放任何奖励';END CASE;
END$$DELIMITER ;

在这个示例中:

  • CASE salary_grade 表示根据 salary_grade 的值进行条件判断。
  • WHEN 1 THEN 表示如果 salary_grade 等于 1,则执行 SELECT '发放奖金';
  • WHEN 2 THEN 表示如果 salary_grade 等于 2,则执行 SELECT '发放小礼品';
  • WHEN 3 THEN 表示如果 salary_grade 等于 3,则执行 SELECT '发放感谢信';
  • ELSE 表示如果 salary_grade 不等于 1、2 或 3,则执行 SELECT '不发放任何奖励';

调用上述存储过程,传入不同的 salary_grade 值:

CALL CheckBonus(1); -- 输出:发放奖金
CALL CheckBonus(2); -- 输出:发放小礼品
CALL CheckBonus(3); -- 输出:发放感谢信
CALL CheckBonus(4); -- 输出:不发放任何奖励
4.LOOP 循环

语法:

LOOP-- 循环体中的语句
END LOOP;

示例:
以下是一个使用 LOOP 循环的存储过程示例,该存储过程将表中的员工工资依次增加 100,直到工资超过 10000:

DELIMITER $$CREATE PROCEDURE IncreaseSalary()
BEGINDECLARE employee_id INT DEFAULT 1;DECLARE current_salary INT;my_loop: LOOPSELECT salary INTO current_salaryFROM employeesWHERE employee_id = employee_id;IF current_salary IS NULL THENLEAVE my_loop;END IF;IF current_salary < 10000 THENUPDATE employeesSET salary = salary + 100WHERE employee_id = employee_id;END IF;SET employee_id = employee_id + 1;END LOOP my_loop;
END$$DELIMITER ;
5.REPEAT 循环

语法:

REPEAT-- 循环体中的语句
UNTIL 条件
END REPEAT;

示例:
以下是一个使用 REPEAT 循环的存储过程示例,该存储过程将表中的员工工资依次增加 100,直到工资超过 10000:

DELIMITER $$CREATE PROCEDURE IncreaseSalary()
BEGINDECLARE employee_id INT DEFAULT 1;DECLARE current_salary INT;REPEATSELECT salary INTO current_salaryFROM employeesWHERE employee_id = employee_id;IF current_salary IS NOT NULL THENIF current_salary < 10000 THENUPDATE employeesSET salary = salary + 100WHERE employee_id = employee_id;END IF;ELSELEAVE;END IF;SET employee_id = employee_id + 1;UNTIL current_salary IS NULLEND REPEAT;
END$$DELIMITER ;

(五)练习

练习一:创建和调用存储过程

创建一个存储过程,用于查询指定部门的员工数量。存储过程名称为 GetEmployeeCountByDepartment,参数为部门编号(@department_id)。
调用这个存储过程,查询部门编号为 10 的员工数量。
答案:

DELIMITER $$CREATE PROCEDURE GetEmployeeCountByDepartment(IN department_id INT)
BEGINSELECT COUNT(*) AS EmployeeCountFROM employeesWHERE department_id = department_id;
END$$DELIMITER ;CALL GetEmployeeCountByDepartment(10);
练习二:使用输出参数

创建一个存储过程,用于计算两个数的乘积,并将结果通过输出参数返回。存储过程名称为 MultiplyTwoNumbers,输入参数为两个数字(@number1@number2),输出参数为乘积(@product)。
调用这个存储过程,计算 4 和 6 的乘积,并将结果存储到一个变量中。
答案:

DELIMITER $$CREATE PROCEDURE MultiplyTwoNumbers(IN number1 INT, IN number2 INT, OUT product INT)
BEGINSET product = number1 * number2;
END$$DELIMITER ;SET @result = 0;
CALL MultiplyTwoNumbers(4, 6, @result);
SELECT @result AS Product;
练习三:控制流语句应用

创建一个存储过程,用于判断一个数字是否为偶数。如果是偶数,打印“偶数”,否则打印“奇数”。存储过程名称为 CheckEvenOdd,输入参数为数字(@number)。
调用这个存储过程,判断数字 7 是否为偶数。
答案:

DELIMITER $$CREATE PROCEDURE CheckEvenOdd(IN number INT)
BEGINIF number % 2 = 0 THENSELECT '偶数';ELSESELECT '奇数';END IF;
END$$DELIMITER ;CALL CheckEvenOdd(7);

二、变量

(一)局部变量

1.定义

局部变量是在存储过程、函数或语句块中声明的变量,其作用域仅限于声明它的存储过程、函数或语句块内部。

2.声明

使用 DECLARE 语句声明局部变量:

DECLARE variable_name variable_data_type [DEFAULT default_value];
  • variable_name:变量的名称,用于在存储过程中引用该变量。
  • variable_data_type:变量的数据类型,如 INTVARCHARDATE 等。
  • DEFAULT default_value(可选):为变量指定默认值。如果不指定默认值,则变量的初始值为 NULL
3.赋值

可以使用 SET 语句或在 SELECT 语句中使用 INTO 子句为局部变量赋值:

SET variable_name = value;

SELECT column INTO variable_name
FROM table_name
WHERE condition;

示例:

DELIMITER $$CREATE PROCEDURE GetEmployeeSalary(IN employee_id INT)
BEGIN-- 声明局部变量DECLARE employee_salary DECIMAL(10, 2);-- 使用 SELECT ... INTO ... 语句查询员工的工资并赋值给局部变量SELECT salary INTO employee_salaryFROM employeesWHERE employee_id = employee_id;-- 输出查询结果SELECT employee_salary AS Salary;
END$$DELIMITER ;
4.作用域

局部变量的作用域仅限于声明它的存储过程、函数或语句块内部,存储过程或函数执行完毕后,局部变量被销毁。

(二)全局变量

1.定义

全局变量是在整个数据库会话中有效的变量,其值在会话期间保持不变,直到显式地更改它。

2.声明

全局变量不需要显式声明,它们是 MySQL 内置的系统变量,通常以 @@ 开头。例如:

SELECT @@global.variable_name;

SET GLOBAL variable_name = value;
3.赋值

可以使用 SET GLOBAL 语句或 SET @@global.variable_name 语法为全局变量赋值:

SET GLOBAL variable_name = value;

SET @@global.variable_name = value;
4.作用域

全局变量的作用域是整个数据库会话,所有用户都可以访问和修改全局变量的值,但修改后的值仅对当前会话有效,不会影响其他会话。

(三)示例

1.局部变量示例

以下是一个存储过程示例,展示了如何声明和使用局部变量:

DELIMITER $$CREATE PROCEDURE CalculateTotal(IN order_id INT, OUT total DECIMAL(10, 2))
BEGIN-- 声明局部变量DECLARE item_price DECIMAL(10, 2);DECLARE item_quantity INT;DECLARE total_items INT DEFAULT 0;DECLARE total_amount DECIMAL(10, 2) DEFAULT 0.0;-- 查询订单中的商品数量SELECT COUNT(*)INTO total_itemsFROM order_itemsWHERE order_id = order_id;-- 遍历订单中的每个商品DECLARE item_cursor CURSOR FORSELECT price, quantityFROM order_itemsWHERE order_id = order_id;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET total_items = 0;OPEN item_cursor;fetch_loop: LOOPFETCH item_cursor INTO item_price, item_quantity;IF total_items = 0 THENLEAVE fetch_loop;END IF;-- 计算每个商品的总价并累加到总金额SET total_amount = total_amount + (item_price * item_quantity);END LOOP;CLOSE item_cursor;-- 将总金额赋值给输出参数SET total = total_amount;
END$$DELIMITER ;

在上述存储过程中:

  • 使用 DECLARE 声明了多个局部变量,包括 item_priceitem_quantitytotal_itemstotal_amount
  • 这些变量在存储过程的逻辑中用于存储临时数据,如商品价格、数量、订单中商品的总数以及订单的总金额。
  • 变量 total_itemstotal_amount 被赋予了默认值,分别是 00.0
  • 使用 SET 语句为变量赋值,例如 SET total_amount = total_amount + (item_price * item_quantity);
2.全局变量示例

以下是一个示例,展示了如何使用全局变量:

-- 查看全局变量的值
SELECT @@global.max_connections;-- 设置全局变量的值
SET GLOBAL max_connections = 1000;-- 或者
SET @@global.max_connections = 1000;

在上述示例中:

  • 使用 SELECT @@global.max_connections; 查看了全局变量 max_connections 的值。
  • 使用 SET GLOBAL max_connections = 1000;SET @@global.max_connections = 1000; 设置了全局变量 max_connections 的值。

(四)面试常问问题

1.局部变量和全局变量的区别是什么?
  • 作用域:局部变量的作用域仅限于声明它的存储过程、函数或语句块内部;全局变量的作用域是整个数据库会话。
  • 声明方式:局部变量使用 DECLARE 语句声明;全局变量不需要显式声明,使用 @@global.variable_nameSET GLOBAL 语句。
  • 赋值方式:局部变量使用 SET 语句或 SELECT ... INTO ... 语句赋值;全局变量使用 SET GLOBAL 语句或 SET @@global.variable_name 语法赋值。
  • 生命周期:局部变量的生命周期与存储过程或函数的执行周期相同;全局变量的生命周期是整个数据库会话。
2.如何声明和使用局部变量?
  • 使用 DECLARE 语句声明局部变量,例如 DECLARE variable_name variable_data_type [DEFAULT default_value];
  • 使用 SET 语句或 SELECT ... INTO ... 语句为局部变量赋值,例如 SET variable_name = value;SELECT column INTO variable_name FROM table_name WHERE condition;
  • 局部变量的作用域仅限于声明它的存储过程、函数或语句块内部,存储过程或函数执行完毕后,局部变量被销毁。
3.如何查看和设置全局变量的值?
  • 使用 SELECT @@global.variable_name; 查看全局变量的值。
  • 使用 SET GLOBAL variable_name = value;SET @@global.variable_name = value; 设置全局变量的值。
4.在存储过程中如何使用局部变量?
  • 在存储过程的开始部分使用 DECLARE 语句声明局部变量。
  • 使用 SET 语句或 SELECT ... INTO ... 语句为局部变量赋值。
  • 在存储过程的逻辑中通过变量名直接引用和操作局部变量。
5.全局变量和局部变量的命名冲突如何解决?
  • 全局变量和局部变量的命名冲突通常不会发生,因为它们的作用域不同。全局变量以 @@global. 开头,而局部变量在存储过程内部声明和使用。
  • 如果需要在存储过程中访问全局变量,可以显式地使用 @@global. 前缀来区分,例如 SELECT @@global.max_connections;

附:【局部变量 用户定义的变量(带@的变量) 全局变量 】三者对比

特性局部变量用户定义的变量(带@的变量)全局变量
作用域仅限于声明它的存储过程、函数或语句块内部整个数据库会话整个数据库服务器
声明方式使用DECLARE语句
示例:DECLARE variable_name variable_data_type [DEFAULT default_value];
使用SET语句
示例:SET @variable_name = value;
使用SET GLOBAL语句或SET @@global.语法
示例:SET GLOBAL variable_name = value;SET @@global.variable_name = value;
赋值方式使用SET语句或SELECT ... INTO ...语句
示例:SET variable_name = value;SELECT column INTO variable_name FROM table_name WHERE condition;
使用SET语句
示例:SET @variable_name = value;
使用SET GLOBAL语句或SET @@global.语法
示例:SET GLOBAL variable_name = value;SET @@global.variable_name = value;
生命周期存储过程或函数执行完毕后销毁会话结束时销毁服务器重启或显式更改时更新
用途存储临时数据,参与计算或作为逻辑控制的依据存储临时值,传递数据,接收存储过程的输出参数配置数据库服务器的行为,影响所有会话
示例代码
  • 局部变量示例

    DELIMITER $$
    CREATE PROCEDURE CalculateTotal(IN order_id INT, OUT total DECIMAL(10, 2))
    BEGINDECLARE item_price DECIMAL(10, 2);DECLARE item_quantity INT;DECLARE total_items INT DEFAULT 0;DECLARE total_amount DECIMAL(10, 2) DEFAULT 0.0;-- 其他逻辑...
    END$$
    DELIMITER ;
    
  • 用户定义的变量(带@的变量)示例

    SET @result = 0;
    CALL AddTwoNumbers(5, 3, @result);
    SELECT @result AS Sum;
    
  • 全局变量示例

    SELECT @@global.max_connections;
    SET GLOBAL max_connections = 1000;
    
详细解释
  1. 作用域

    • 局部变量:仅限于声明它的存储过程、函数或语句块内部。一旦存储过程或函数执行完毕,局部变量将被销毁。
    • 用户定义的变量(带 @ 的变量):整个数据库会话。在同一个会话中,这些变量可以跨多个 SQL 语句使用,直到会话结束。
    • 全局变量:整个数据库服务器。所有会话都可以访问和修改全局变量的值,修改后会影响所有当前和未来的会话。
  2. 声明方式

    • 局部变量:使用 DECLARE 语句在存储过程或函数的开始部分声明。
    • 用户定义的变量(带 @ 的变量):使用 SET 语句在会话中声明和初始化。
    • 全局变量:使用 SET GLOBAL 语句或 SET @@global. 语法声明和赋值。
  3. 赋值方式

    • 局部变量:使用 SET 语句或 SELECT ... INTO ... 语句赋值。
    • 用户定义的变量(带 @ 的变量):使用 SET 语句赋值。
    • 全局变量:使用 SET GLOBAL 语句或 SET @@global. 语法赋值。
  4. 生命周期

    • 局部变量:存储过程或函数执行完毕后销毁。
    • 用户定义的变量(带 @ 的变量):会话结束时销毁。
    • 全局变量:服务器重启或显式更改时更新。
  5. 用途

    • 局部变量:用于存储临时数据,参与计算或作为逻辑控制的依据。
    • 用户定义的变量(带 @ 的变量):用于存储临时值,传递数据,接收存储过程的输出参数。
    • 全局变量:用于配置数据库服务器的行为,影响所有会话。

三、 游标(CURSOR)

定义

游标(Cursor)是数据库中一个临时的工作区,用于存储和操作查询结果集中的数据。

声明

DECLARE cursor_name CURSOR FOR select_statement;

打开游标

OPEN cursor_name;

获取数据

FETCH cursor_name INTO variable_name [, variable_name ...];

关闭游标

CLOSE cursor_name;

示例

以下是一个使用游标的存储过程示例,该存储过程将表中的员工工资依次增加 100,直到工资超过 10000:

DELIMITER $$CREATE PROCEDURE IncreaseSalary()
BEGINDECLARE employee_id INT;DECLARE current_salary INT;DECLARE done INT DEFAULT 0;DECLARE cursor_name CURSOR FORSELECT employee_id, salaryFROM employees;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET done = 1;OPEN cursor_name;my_loop: LOOPFETCH cursor_name INTO employee_id, current_salary;IF done = 1 THENLEAVE my_loop;END IF;IF current_salary < 10000 THENUPDATE employeesSET salary = salary + 100WHERE employee_id = employee_id;END IF;END LOOP my_loop;CLOSE cursor_name;
END$$DELIMITER ;

四、处理程序(HANDLER)

定义

处理程序(Handler)用于捕获和处理存储过程或函数执行过程中发生的特定条件或异常。

声明

DECLARE [CONTINUE | EXIT | UNDO] HANDLER FOR condition-- 处理程序中的语句

示例

以下是一个使用处理程序的存储过程示例,该存储过程捕获了查询结果为空的情况:

DELIMITER $$CREATE PROCEDURE GetEmployeeSalary(IN employee_id INT)
BEGINDECLARE employee_salary DECIMAL(10, 2);DECLARE done INT DEFAULT 0;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET done = 1;SELECT salary INTO employee_salaryFROM employeesWHERE employee_id = employee_id;IF done = 1 THENSELECT '未找到员工' AS message;ELSESELECT employee_salary AS Salary;END IF;
END$$DELIMITER ;

五、 事务控制

事务概述

事务是一组 SQL 语句的集合,这些语句要么全部成功执行,要么全部不执行。事务的目的是确保数据的完整性和一致性。

BEGIN、COMMIT、ROLLBACK 语句

  • BEGIN 或 START TRANSACTION:开始一个新的事务。
  • COMMIT:提交当前事务,使事务中的所有更改永久生效。
  • ROLLBACK:回滚当前事务,撤销事务中的所有更改。
  • SAVEPOINT:设置一个保存点,可以在事务中回滚到这个点。

示例

以下是一个使用事务控制的存储过程示例,该存储过程更新员工的工资,并在发生错误时回滚事务:

DELIMITER $$CREATE PROCEDURE UpdateEmployeeSalary(IN employee_id INT, IN new_salary DECIMAL(10, 2))
BEGINDECLARE exit_handler INT DEFAULT 0;DECLARE EXIT HANDLER FOR SQLEXCEPTIONBEGINSET exit_handler = 1;END;START TRANSACTION;UPDATE employeesSET salary = new_salaryWHERE employee_id = employee_id;IF exit_handler = 1 THENROLLBACK;SELECT '更新失败' AS message;ELSECOMMIT;SELECT '更新成功' AS message;END IF;
END$$DELIMITER ;

六、 动态 SQL

动态 SQL 概述

动态 SQL 是指在运行时生成和执行 SQL 语句的技术。

PREPARE、EXECUTE、DEALLOCATE PREPARE 语句

  • PREPARE:准备执行 SQL 语句。
  • EXECUTE:执行准备好的 SQL 语句。
  • DEALLOCATE PREPARE:释放准备好的 SQL 语句。

示例

以下是一个使用动态 SQL 的存储过程示例,该存储过程根据表名动态生成和执行 SQL 语句:

DELIMITER $$CREATE PROCEDURE DynamicSQL(IN table_name VARCHAR(100))
BEGINDECLARE sql_statement VARCHAR(255);SET sql_statement = CONCAT('SELECT * FROM ', table_name);PREPARE stmt FROM sql_statement;EXECUTE stmt;DEALLOCATE PREPARE stmt;
END$$DELIMITER ;

八、 存储过程案例:

批量数据处理示例:批量更新用户积分

以下是一个存储过程示例,该存储过程根据用户的消费金额批量更新用户的积分:

DELIMITER $$CREATE PROCEDURE UpdateUserPoints()
BEGINDECLARE user_id INT;DECLARE consumption DECIMAL(10, 2);DECLARE done INT DEFAULT 0;DECLARE cursor_name CURSOR FORSELECT id, consumptionFROM users;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET done = 1;OPEN cursor_name;my_loop: LOOPFETCH cursor_name INTO user_id, consumption;IF done = 1 THENLEAVE my_loop;END IF;UPDATE usersSET points = points + consumption * 10WHERE id = user_id;END LOOP my_loop;CLOSE cursor_name;
END$$DELIMITER ;

数据校验示例:校验用户输入数据

以下是一个存储过程示例,该存储过程校验用户输入的用户名和密码是否符合要求:

DELIMITER $$CREATE PROCEDURE ValidateUser(IN username VARCHAR(100), IN password VARCHAR(100))
BEGINDECLARE valid INT DEFAULT 0;IF LENGTH(username) >= 6 AND LENGTH(password) >= 8 THENSET valid = 1;END IF;SELECT valid AS IsValid;
END$$DELIMITER ;

复杂业务逻辑封装示例:计算订单总金额

以下是一个存储过程示例,该存储过程根据订单中的商品信息计算订单的总金额:

DELIMITER $$CREATE PROCEDURE CalculateOrderTotal(IN order_id INT, OUT total DECIMAL(10, 2))
BEGINDECLARE item_price DECIMAL(10, 2);DECLARE item_quantity INT;DECLARE total_items INT DEFAULT 0;DECLARE total_amount DECIMAL(10, 2) DEFAULT 0.0;DECLARE cursor_name CURSOR FORSELECT price, quantityFROM order_itemsWHERE order_id = order_id;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET total_items = 0;OPEN cursor_name;my_loop: LOOPFETCH cursor_name INTO item_price, item_quantity;IF total_items = 0 THENLEAVE my_loop;END IF;SET total_amount = total_amount + (item_price * item_quantity);END LOOP my_loop;CLOSE cursor_name;SET total = total_amount;
END$$DELIMITER ;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/89407.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/89407.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/89407.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NLP文本数据增强

文章目录 文本数据增强同义词替换示例Python代码示例 随机插入示例Python代码示例 随机删除示例Python代码示例 回译&#xff08;Back Translation&#xff09;示例Python代码示例 文本生成模型应用方式示例Python代码示例 总结 文本数据增强 数据增强通过对原始数据进行变换、…

(LeetCode 每日一题) 594. 最长和谐子序列 (哈希表)

题目&#xff1a;594. 最长和谐子序列 思路&#xff1a;哈希表&#xff0c;时间复杂度0(n)。 用哈希表mp来记录每个元素值出现的次数&#xff0c;然后枚举所有值x&#xff0c;看其x1是否存在&#xff0c;存在的话就可以维护最长的子序列长度mx。 C版本&#xff1a; class Sol…

FreePDF:让看英文文献像喝水一样简单

前言 第一次看英文文献&#xff0c;遇到不少看不懂的英文单词&#xff0c;一个个查非常费劲。 后来&#xff0c;学会了使用划词翻译&#xff0c;整段整段翻译查看&#xff0c;极大提升看文献效率。 最近&#xff0c;想到了一种更快的看文献的方式&#xff0c;那就是把英文PD…

Scikit-learn:机器学习的「万能工具箱」

——三行代码构建AI模型的全栈指南** ### **一、诞生背景&#xff1a;让机器学习从实验室走向大众** **2010年前的AI困境**&#xff1a; - 学术界模型难以工程化 - 算法实现碎片化&#xff08;MATLAB/C主导&#xff09; - 企业应用门槛极高 > **破局者**&#xff1a;Da…

GPT-1论文阅读:Improving Language Understanding by Generative Pre-Training

这篇论文提出了 GPT (Generative Pre-Training) 模型&#xff0c;这是 GPT系列&#xff08;包括 GPT-2, GPT-3, ChatGPT, GPT-4 等&#xff09;的奠基之作。它标志着自然语言处理领域向大规模无监督预训练任务特定微调范式的重大转变&#xff0c;并取得了显著的成功。 文章链接…

Hadoop大数据-Mysql的数据同步工具Maxwell安装与使用( 详解)

目录 一、前置基础知识 1、主从复制&#xff08;Replication&#xff09; 2、数据恢复 3、数据库热备 4、读写分离 5、存储位置及命名 二、Maxwell简介 1、简介 2、Maxwell同步数据特点 2.1.历史记录同步 2.2.断点续传 三、前期准备 1、查看网卡&#xff1a; 2、…

分布式系统的一致性模型:核心算法与工程实践

目录 一、分布式一致性的核心挑战二、主流一致性算法原理剖析1. Paxos&#xff1a;理论基础奠基者2. Raft&#xff1a;工业级首选方案3. ZAB&#xff1a;ZooKeeper的引擎 三、算法实现与代码实战Paxos基础实现&#xff08;Python伪代码&#xff09;Raft日志复制核心逻辑 四、关…

Apache HTTP Server部署全攻略

httpd 简介 httpd&#xff08;Apache HTTP Server&#xff09;是一款历史悠久的开源 Web 服务器软件&#xff0c;由 Apache 软件基金会开发和维护。自 1995 年首次发布以来&#xff0c;Apache 一直是 Web 服务器领域的领导者&#xff0c;以其稳定性、安全性和灵活性著称。根据…

信号处理学习——文献精读与code复现之TFN——嵌入时频变换的可解释神经网络(下)

书接上文: 信号处理学习——文献精读与code复现之TFN——嵌入时频变换的可解释神经网络&#xff08;上&#xff09;-CSDN博客 接下来是重要的代码复现&#xff01;&#xff01;&#xff01;GitHub - ChenQian0618/TFN: this is the open code of paper entitled "TFN: A…

线上故障排查:签单合同提交报错分析-对接e签宝

在企业管理系统中&#xff0c;合同生成与签署环节至关重要&#xff0c;尤其是在使用第三方平台进行电子签署时。本文将通过实际的报错信息&#xff0c;分析如何进行线上故障排查&#xff0c;解决合同生成过程中出现的问题。 #### 1. 错误描述 在尝试生成合同并提交至电子签署…

知攻善防靶机 Linux easy溯源

知攻善防 【护网训练-Linux】应急响应靶场-Easy溯源 小张是个刚入门的程序猿&#xff0c;在公司开发产品的时候突然被叫去应急&#xff0c;小张心想"早知道简历上不写会应急了"&#xff0c;于是call了运维小王的电话&#xff0c;小王说"你面试的时候不是说会应急…

原神八分屏角色展示页面(纯前端html,学习交流)

原神八分屏角色展示页面 - 一个精美的前端交互项目 项目简介 这是一个基于原神游戏角色制作的八分屏展示页面&#xff0c;采用纯前端技术实现&#xff0c;包含了丰富的动画效果、音频交互和视觉设计。项目展示了一些热门原神角色&#xff0c;每个角色都有独立的介绍页面和专属…

华为认证二选一:物联网 VS 人工智能,你的赛道在哪里?

一篇不讲情怀只讲干货的科普指南 一、华为物联网 & 人工智能到底在搞什么&#xff1f; 华为物联网&#xff08;IoT&#xff09; 的核心是 “万物互联”。 通过传感器、通信技术&#xff08;如NB-IoT/5G&#xff09;、云计算平台&#xff08;如OceanConnect&#xff09;&…

CloudLens for PolarDB:解锁数据库性能优化与智能运维的终极指南

随着企业数据规模的爆炸式增长,数据库性能管理已成为技术团队的关键挑战。本文深入探讨如何利用CloudLens for PolarDB实现高级监控、智能诊断和自动化运维,帮助您构建一个自我修复、高效运行的数据库环境。 引言:数据库监控的演进 在云原生时代,传统的数据库监控方式已不…

MySQL中TINYINT/INT/BIGINT的典型应用场景及实例

以下是MySQL中TINYINT/INT/BIGINT的典型应用场景及实例说明&#xff1a; 一、TINYINT&#xff08;1字节&#xff09; 1.状态标识 -- 用户激活状态&#xff08;0未激活/1已激活&#xff09; ALTER TABLE users ADD is_active TINYINT(1) DEFAULT 0; 适用于布尔值存储和状态码…

YOLOv13:最新的YOLO目标检测算法

[2506.17733] YOLOv13: Real-Time Object Detection with Hypergraph-Enhanced Adaptive Visual Perception Github: https://github.com/iMoonLab/yolov13 YOLOv13&#xff1a;利用超图增强型自适应视觉感知进行实时物体检测 主要的创新点提出了HyperACE机制、FullPAD范式、轻…

【深入浅出:计算流体力学(CFD)基础与核心原理--从NS方程到工业仿真实践】

关键词&#xff1a;#CFD、#Navier-Stokes方程、#有限体积法、#湍流模型、#网格收敛性、#工业仿真验证 一、CFD是什么&#xff1f;为何重要&#xff1f; 计算流体力学&#xff08;Computational Fluid Dynamics, CFD&#xff09; 是通过数值方法求解流体流动控制方程&#xff0…

qt常用控件--04

文章目录 qt常用控件labelLCD NumberProgressBar结语 很高兴和大家见面&#xff0c;给生活加点impetus&#xff01;&#xff01;开启今天的编程之路&#xff01;&#xff01; 今天我们进一步c11中常见的新增表达 作者&#xff1a;٩( ‘ω’ )و260 我的专栏&#xff1a;qt&am…

Redmine:一款基于Web的开源项目管理软件

Redmine 是一款基于 Ruby on Rails 框架开发的开源、跨平台、基于 Web 的项目管理、问题跟踪和文档协作软件。 Redmine 官方网站自身就是基于它构建的一个 Web 应用。 功能特性 Redmine 的主要特点和功能包括&#xff1a; 多项目管理&#xff1a; Redmine 可以同时管理多个项…

FPGA FMC 接口

1 FMC 介绍 FMC 接口即 FPGA Mezzanine Card 接口,中文名为 FPGA 中间层板卡接口。以下是对它的详细介绍: 标准起源:2008 年 7 月,美国国家标准协会(ANSI)批准和发布了 VITA 57 FMC 标准。该标准由从 FPGA 供应商到最终用户的公司联盟开发,旨在为位于基板(载卡)上的 …