mysql菜鸟教程
14.4 带参数的存储过程
在上一节中,我们学习了存储过程的基本概念和创建方法。但那些存储过程都是“死”的——它们只能执行固定的操作。现实中的业务需求往往是变化的,比如查询不同员工的信息、按照不同百分比加薪等。这就需要存储过程能够接收外部传入的值,并根据这些值执行相应的逻辑。参数正是为了解决这个问题而设计的。
一、为什么需要参数?
参数让存储过程变得更加灵活和通用。通过参数,你可以:
将外部数据传递给存储过程,使其执行不同的操作。
从存储过程中获取计算结果或状态信息。
实现数据的双向传递(传入并返回修改后的值)。
二、参数的类型
MySQL 存储过程支持三种类型的参数,每种类型都有其特定的用途:
参数定义语法
在创建存储过程时,参数定义放在过程名后面的括号内:
CREATE PROCEDURE 过程名( [IN | OUT | INOUT] 参数名 数据类型, [IN | OUT | INOUT] 参数名 数据类型, ... ) BEGIN -- 过程体 END;
如果不指定参数类型,默认为 IN。
数据类型可以是任何有效的 MySQL 数据类型(如 INT、VARCHAR、DECIMAL、DATE 等)。
三、实战示例
我们将继续使用 employees 表来演示不同类型的参数。
CREATE TABLE employees (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
department VARCHAR(50),
salary DECIMAL(10,2),
hire_date DATE
);
INSERT INTO employees (name, department, salary, hire_date) VALUES
('张三', '技术部', 8000, '2023-01-10'),
('李四', '市场部', 7000, '2023-02-15'),
('王五', '技术部', 9000, '2023-03-20'),
('赵六', '销售部', 6000, '2023-04-01');示例1:使用 IN 参数查询员工
创建一个存储过程,根据传入的员工姓名(或ID)查询该员工信息。
DELIMITER // CREATE PROCEDURE GetEmployeeByName(IN emp_name VARCHAR(50)) BEGIN SELECT * FROM employees WHERE name = emp_name; END // DELIMITER ;
调用:
CALL GetEmployeeByName('张三');如果传入的名字不存在,结果集为空。
扩展:可以传入多个参数,例如同时查询部门和最低工资:
DELIMITER //
CREATE PROCEDURE GetEmployeesByDeptAndSalary(
IN dept VARCHAR(50),
IN min_salary DECIMAL(10,2)
)
BEGIN
SELECT * FROM employees
WHERE department = dept AND salary >= min_salary;
END //
DELIMITER ;
CALL GetEmployeesByDeptAndSalary('技术部', 8000);示例2:使用 OUT 参数返回统计值
有时我们不需要返回结果集,而只需要获取一个计算值(如总人数、平均工资)。这时可以用 OUT 参数。
DELIMITER // CREATE PROCEDURE CountEmployeesByDept( IN dept VARCHAR(50), OUT total INT ) BEGIN SELECT COUNT(*) INTO total FROM employees WHERE department = dept; END // DELIMITER ;
调用:
CALL CountEmployeesByDept('技术部', @count);
SELECT @count; -- 输出 2这里使用了 SELECT ... INTO 将查询结果直接赋值给 OUT 参数。
示例3:使用 INOUT 参数修改并返回值
INOUT 参数既接收外部值,又可以将修改后的值传回。例如,我们想对员工的工资进行调整,并返回调整后的新工资。
DELIMITER // CREATE PROCEDURE AdjustSalary( IN emp_id INT, INOUT amount DECIMAL(10,2) -- 传入调整金额,返回调整后工资 ) BEGIN -- 获取当前工资 DECLARE current_salary DECIMAL(10,2); SELECT salary INTO current_salary FROM employees WHERE id = emp_id; -- 更新工资 UPDATE employees SET salary = current_salary + amount WHERE id = emp_id; -- 将 amount 设置为新工资 SET amount = current_salary + amount; END // DELIMITER ;
调用:
SET @adjust = 500; -- 要增加的金额 CALL AdjustSalary(1, @adjust); SELECT @adjust; -- 返回调整后的工资(如 8500)
注意:调用时必须使用变量(以 @ 开头),不能直接传常量。
三、结合流程控制与参数
参数可以与流程控制语句结合,实现更复杂的逻辑。例如,根据不同的部门实施不同的加薪策略。
DELIMITER // CREATE PROCEDURE RaiseSalaryByDept( IN dept_name VARCHAR(50), IN percent DECIMAL(5,2), OUT affected_rows INT, OUT new_avg DECIMAL(10,2) ) BEGIN -- 更新工资 UPDATE employees SET salary = salary * (1 + percent/100) WHERE department = dept_name; -- 获取受影响行数 SET affected_rows = ROW_COUNT(); -- 计算新的平均工资 SELECT AVG(salary) INTO new_avg FROM employees WHERE department = dept_name; END // DELIMITER ;
调用:
CALL RaiseSalaryByDept('技术部', 10, @rows, @avg);
SELECT @rows, @avg;四、注意事项
参数命名:避免与列名相同,以免引起歧义。通常参数名加前缀(如 p_、in_)或使用有意义的名称。
数据类型匹配:传入的参数值必须与参数类型兼容,否则会出错或产生隐式转换。
OUT/INOUT 参数必须使用变量:调用时不能直接传递常量,必须使用用户变量(如 @var)。
作用域:参数在整个存储过程内部有效,其作用域类似于局部变量。
NULL 值处理:参数可以接受 NULL 值,但在使用时需要合理处理,避免导致意外结果。
OUT 参数不接收输入值:即使你在调用时给 OUT 参数变量赋了值,该值也不会传入存储过程。存储过程开始执行时,OUT 参数的值为 NULL。
INOUT 参数会接收传入的值,并在过程体内可以修改。
小结
存储过程通过参数实现与调用者的数据交换。
IN 参数用于传入值,过程内部只读。
OUT 参数用于返回计算值,过程内部赋值,调用者通过变量获取。
INOUT 参数双向传递,可以修改并返回。
参数极大地增强了存储过程的灵活性和实用性,是编写可复用业务逻辑的基础。

发表评论
所有评论