当前位置: 首页 > news >正文

SQL 进阶:触发器、存储过程

文章目录

  • 一、触发器
    • 1.1 定义
    • 1.2 创建语法
    • 1.3 关键变量:NEW 与 OLD
    • 1.4 案例:下单减库存
      • 准备表与初始数据
      • 需求 1:新增订单时自动减固定库存(减少 2 个)
      • 需求 2:修改订单数量时,自动调整库存(动态适配数量)
  • 二、存储过程
    • 2.1 核心特性
    • 2.2 创建语法与参数类型
    • 2.3 示例:按参数类型分类
      • IN 参数示例(仅输入值)
      • OUT 参数示例(仅输出结果)
      • INOUT 参数示例(双向传递)

一、触发器

触发器是与表关联的 “自动执行的存储过程”,无需手动调用,当表发生INSERT/UPDATE/DELETE(DML 操作)时自动触发,用于保证数据完整性(如 “下单减库存”)。

1.1 定义

定义:与表绑定的特殊逻辑,由 “事件”(DML 操作)触发,不可手动调用,执行结果依赖于触发事件。

4 要素(创建触发器必须指定):

  1. 监视对象:触发逻辑绑定的(只能是单个表)。
  2. 监视事件:触发触发器的 DML 操作,可选INSERT(插入)、UPDATE(更新)、DELETE(删除)。
  3. 触发时间:事件执行的时机,可选BEFORE(事件前执行)、AFTER(事件后执行)。
  4. 触发动作:触发器触发后执行的逻辑(如UPDATE其他表、INSERT日志记录)。

1.2 创建语法

CREATE TRIGGER trigger_name  -- 触发器名称(自定义,需唯一)
trigger_time trigger_event    -- 触发时间(BEFORE/AFTER)+ 监视事件(INSERT/UPDATE/DELETE)
ON tbl_name FOR EACH ROW      -- 绑定的表(tbl_name),FOR EACH ROW表示“每行触发一次”
[trigger_order]               -- 可选,多个触发器的执行顺序(FOLLOWS/PRECEDES 其他触发器名)
trigger_body;                 -- 触发动作(单个语句可直接写,多个语句需用BEGIN...END包裹)

1.3 关键变量:NEW 与 OLD

用于获取触发事件中 “数据的变化”,不同事件对应的变量含义不同:

触发事件NEW 变量含义OLD 变量含义
INSERT将要 / 已经插入的新数据无(插入操作无原数据)
DELETE无(删除操作无新数据)将要 / 已经删除的原数据
UPDATE将要 / 已经修改为的新数据将要 / 已经修改的原数据
  • 使用方式:NEW.columnName(获取新数据的某列值)、OLD.columnName(获取原数据的某列值),columnName 为绑定表的列名。

1.4 案例:下单减库存

需求:当用户在order(订单表)中插入新订单时,自动减少goods(商品表)中对应商品的库存(库存 = 原库存 - 下单数量)。

准备表与初始数据

-- 1. 商品表:存储商品ID、名称、库存
CREATE TABLE `goods` (`id` INT PRIMARY KEY auto_increment,  -- 商品ID`name` VARCHAR (32),                  -- 商品名称`num` SMALLINT DEFAULT 0              -- 库存数量
);-- 2. 订单表:存储订单ID、商品ID、下单数量
CREATE TABLE `order` (`id` INT PRIMARY KEY auto_increment,  -- 订单ID`goods_id` INT,                       -- 关联商品表的ID`quantity` SMALLINT COMMENT '下单数量' -- 购买数量
);-- 3. 插入初始商品数据
INSERT INTO goods VALUES (NULL, 'C++', 40),   -- 商品1:C++教程,库存40(NULL, 'C', 63),     -- 商品2:C教程,库存63(NULL, 'mysql', 87); -- 商品3:MySQL教程,库存87-- 4. 插入初始订单数据(此时无触发器,需手动减库存)
INSERT INTO `order` VALUES (NULL, 1, 3); -- 订单1:买3本C++教程
INSERT INTO `order` VALUES (NULL, 2, 4); -- 订单2:买4本C教程

需求 1:新增订单时自动减固定库存(减少 2 个)

-- 修改分隔符为//(触发器体含多个语句)
DELIMITER //
-- 创建触发器:插入订单后,自动减少商品1的库存2个
CREATE TRIGGER trig_order_1 
AFTER INSERT  -- 触发时间:插入订单后;监视事件:INSERT
ON `order` FOR EACH ROW  -- 绑定订单表,每行订单触发一次
BEGIN-- 触发动作:更新商品表,商品1(id=1)的库存=原库存-2UPDATE goods SET num = num - 2 WHERE id = 1;
END
//
DELIMITER ;-- 测试:插入新订单,触发库存减少
INSERT INTO `order` VALUES (NULL, 1, 1); -- 新增订单:买1本C++教程
SELECT num FROM goods WHERE id=1; -- 结果:原库存40-3(初始订单)-2(触发器)=35

需求 2:修改订单数量时,自动调整库存(动态适配数量)

DELIMITER //
-- 创建触发器:修改订单前,自动调整对应商品的库存
CREATE TRIGGER trig_order_2 
BEFORE UPDATE  -- 触发时间:修改订单前;监视事件:UPDATE
ON `order` FOR EACH ROW 
BEGIN-- 逻辑:库存=原库存 + 订单原数量 - 订单新数量(原数量多退少补)UPDATE goods SET num = num + OLD.quantity - NEW.quantity  -- OLD.quantity=原下单数,NEW=新下单数WHERE id = NEW.goods_id;  -- 关联新订单的商品ID
END
//
DELIMITER ;-- 测试:修改订单1的数量(从3改为5,需多减2个库存)
UPDATE `order` SET quantity = quantity + 2 WHERE id = 1; 
SELECT num FROM goods WHERE id=1; -- 结果:35(需求1后库存) +3(原数量)-5(新数量)=33

二、存储过程

存储过程是 “预编译的 SQL 语句集”,经编译后存储在数据库中,通过 “调用名称 + 参数” 执行,可包含流程控制逻辑,适合实现复杂业务(如批量数据处理)。

2.1 核心特性

  • 预编译:首次执行时编译,后续调用直接使用编译结果,比单次执行多条 SQL 更快。
  • 可编程性:支持IF、WHILE等流程控制,可实现复杂逻辑(如数据校验、批量计算)。
  • 重复使用:一次创建,多次调用,减少重复 SQL 书写,降低维护成本。
  • 减少网络传输:客户端只需发送 “调用指令”,无需传输大量 SQL 语句,节省网络开销。

2.2 创建语法与参数类型

基础语法

CREATE PROCEDURE 过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型…]]  -- 参数列表
) [特性]  -- 可选,如SQL SECURITY DEFINER(按创建者权限执行)
过程体;  -- 业务逻辑,多语句需用BEGIN...END包裹,需配合DELIMITER修改分隔符

参数类型说明

存储过程支持 3 种参数类型,用于实现 “输入值”“输出结果”“输入输出双向传递”:

参数类型核心特点
IN输入参数:调用时必须传入值,存储过程中修改该参数值不影响外部变量,可设默认值。
OUT输出参数:调用时无需传入初始值(传变量名),存储过程中修改后会同步到外部变量
INOUT输入输出参数:调用时需传入初始值,存储过程中修改后同步到外部变量,双向传递。

2.3 示例:按参数类型分类

IN 参数示例(仅输入值)

需求:创建存储过程,接收输入参数p_in,查询参数值并修改,观察外部变量是否变化。

DELIMITER //
CREATE PROCEDURE proc_in_param (IN p_in INT)  -- IN参数:p_in(整数类型)
BEGINSELECT p_in;  -- 第一次查询:输出传入的初始值SET p_in = 2; -- 存储过程中修改参数值为2SELECT p_in;  -- 第二次查询:输出修改后的值(2)
END ;
//
DELIMITER ;-- 调用存储过程
SET @p_in = 1;          -- 定义外部变量,初始值1
CALL proc_in_param (@p_in);  -- 传入外部变量
SELECT @p_in;           -- 查询外部变量:结果仍为1(IN参数修改不影响外部)

OUT 参数示例(仅输出结果)

需求:创建存储过程,通过 OUT 参数输出修改后的值,观察外部变量变化。

DELIMITER //
CREATE PROCEDURE proc_out_param(OUT p_out INT)  -- OUT参数:p_out
BEGINSELECT p_out;  -- 第一次查询:输出初始值(NULL,因OUT参数无需传入初始值)SET p_out = 2; -- 修改参数值为2SELECT p_out;  -- 第二次查询:输出2
END;
//
DELIMITER ;-- 调用存储过程
SET @p_out = 1;         -- 定义外部变量,初始值1(OUT参数会忽略该值)
CALL proc_out_param(@p_out);  -- 传入外部变量
SELECT @p_out;          -- 查询外部变量:结果为2(OUT参数修改同步到外部)

INOUT 参数示例(双向传递)

需求:创建存储过程,接收输入值并修改,同步到外部变量。

DELIMITER //
CREATE PROCEDURE proc_inout_param(INOUT p_inout INT)  -- INOUT参数
BEGINSELECT p_inout;  -- 第一次查询:输出传入的初始值(1)SET p_inout = 2; -- 修改参数值为2SELECT p_inout;  -- 第二次查询:输出2
END;
//
DELIMITER ;-- 调用存储过程
SET @p_inout = 1;       -- 定义外部变量,初始值1
CALL proc_inout_param(@p_inout);  -- 传入外部变量
SELECT @p_inout;        -- 查询外部变量:结果为2(INOUT参数双向传递)
http://www.dtcms.com/a/528335.html

相关文章:

  • ansible快速准备redis集群环境
  • 公司网站制作效果长沙网站制造
  • 数据结构之堆
  • 【Linux学习笔记】日志器与线程池设计
  • 【Linux系统编程】编辑器vim
  • 鸿蒙ArkTS入门教程:小白实战“易经”Demo,详解@State、@Prop与List组件
  • 扩散模型与UNet融合的创新路径
  • 从入门到精通的鸿蒙学习之路——基于鸿蒙6.0时代的生态趋势与实战路径
  • 704.力扣LeetCode_二分查找
  • 如何做企业网站宣传wordpress 显示空白
  • 机器学习库的线性回归预测
  • 旅游网站开发研究背景北京欢迎您
  • 做网站要学什么东西企业网站运维
  • Orleans Grain Directory 系统综合分析文档
  • 从PN结到GPIO工作模式
  • 面向社科研究者:用深度学习做因果推断(三)
  • 深度学习-MNIST手写数字识别(MLP)
  • K8s 静态持久化存储详解
  • wordpress seo 能提高网站速度吗
  • GitHub等平台形成的开源文化正在重塑特尔恩恩
  • 追根索源:换不同的词嵌入(词向量生成方式不同,但词与词关系接近),会出现什么结果?
  • 视频与音频碰撞,谷歌 Veo 3.1,生成“有声电影”,人物对话超震撼
  • 【PID】基本PID控制 chaprt1 学习笔记
  • 【大语言模型 103】推理服务监控:性能指标、故障诊断与自动恢复实战
  • 网站广东海外建设集团有限公司做网站工资多钱
  • Julia 字符串处理指南
  • volatile关键词探秘:从咖啡厅的诡异订单到CPU缓存之谜
  • 嵌入式Lua脚本编程核心概念
  • VScode开发环境搭建(本文为个人学习笔记,内容整理自哔哩哔哩UP主【非学者勿扰】的公开课程。 > 所有知识点归属原作者,仅作非商业用途分享)
  • 基于springboot的车辆管理系统设计与实现