在库存管理场景中,库存余额会随着入库、出库、退货等操作实时变动,手动计算不仅效率低还容易出现数据误差,通过SQL触发器可以在数据发生变动时自动完成库存余额的更新,实现动态库存余额的精准计算。

基础表结构设计
首先需要设计两张核心表,一张是存储当前库存余额的inventory表,另一张是记录所有库存变动明细的inventory_log表。
库存余额表 inventory
该表存储每个商品的当前实时库存数量,结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| product_id | INT | 商品ID,主键 |
| product_name | VARCHAR(100) | 商品名称 |
| stock_balance | INT | 当前库存余额 |
库存变动明细表 inventory_log
该表记录每一次库存变动的详细信息,结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| log_id | INT | 记录ID,主键自增 |
| product_id | INT | 商品ID |
| change_type | VARCHAR(20) | 变动类型:IN表示入库,OUT表示出库 |
| change_num | INT | 变动数量,正数表示增加,负数表示减少 |
| create_time | DATETIME | 变动时间 |
触发器实现逻辑
我们需要针对inventory_log表的插入、更新、删除三种操作分别创建触发器,保证库存余额能跟随明细变动自动更新。
插入明细时更新库存
当新增一条库存变动明细时,根据变动类型和数量自动调整对应商品的库存余额,如果商品不存在则自动插入初始库存记录。
-- 创建插入触发器
DELIMITER //
CREATE TRIGGER update_stock_after_insert
AFTER INSERT ON inventory_log
FOR EACH ROW
BEGIN
-- 判断商品是否已在库存表中存在
IF EXISTS (SELECT 1 FROM inventory WHERE product_id = NEW.product_id) THEN
-- 存在则更新库存余额
UPDATE inventory
SET stock_balance = stock_balance + NEW.change_num
WHERE product_id = NEW.product_id;
ELSE
-- 不存在则插入初始库存记录
INSERT INTO inventory (product_id, product_name, stock_balance)
VALUES (NEW.product_id, (SELECT product_name FROM product WHERE product_id = NEW.product_id), NEW.change_num);
END IF;
END //
DELIMITER ;
更新明细时调整库存
当修改已有的库存变动明细时,需要先撤销原来的变动影响,再应用新的变动影响,保证库存余额准确。
-- 创建更新触发器
DELIMITER //
CREATE TRIGGER update_stock_after_update
AFTER UPDATE ON inventory_log
FOR EACH ROW
BEGIN
-- 先撤销旧变动的影响
UPDATE inventory
SET stock_balance = stock_balance - OLD.change_num
WHERE product_id = OLD.product_id;
-- 再应用新变动的影响
UPDATE inventory
SET stock_balance = stock_balance + NEW.change_num
WHERE product_id = NEW.product_id;
END //
DELIMITER ;
删除明细时回滚库存
当删除一条库存变动明细时,需要把该明细带来的库存变动影响撤销,恢复之前的库存余额。
-- 创建删除触发器
DELIMITER //
CREATE TRIGGER update_stock_after_delete
AFTER DELETE ON inventory_log
FOR EACH ROW
BEGIN
-- 撤销被删除明细的变动影响
UPDATE inventory
SET stock_balance = stock_balance - OLD.change_num
WHERE product_id = OLD.product_id;
END //
DELIMITER ;
功能验证
我们可以通过简单的测试验证触发器的效果,首先插入两条入库明细:
-- 插入两条入库记录,商品1入库100件,商品2入库50件 INSERT INTO inventory_log (product_id, change_type, change_num, create_time) VALUES (1, 'IN', 100, NOW()); INSERT INTO inventory_log (product_id, change_type, change_num, create_time) VALUES (2, 'IN', 50, NOW());
此时查询inventory表,会发现商品1的库存余额为100,商品2的库存余额为50。
再插入一条商品1的出库记录:
-- 商品1出库30件 INSERT INTO inventory_log (product_id, change_type, change_num, create_time) VALUES (1, 'OUT', -30, NOW());
再次查询inventory表,商品1的库存余额会变为70,说明触发器已经自动完成了库存更新。
注意事项
- 触发器中尽量避免复杂的逻辑,防止影响数据操作的性能,如果变动逻辑复杂可以考虑拆分到存储过程中。
- 如果业务中存在批量插入、更新、删除明细的场景,需要评估触发器对批量操作性能的影响,必要时可以暂时禁用触发器执行批量操作后再启用。
- 库存余额的更新需要保证原子性,建议把明细操作和触发器更新放在同一个事务中,避免部分更新导致的数据不一致。
- 如果商品名称等信息会变动,需要在更新商品信息时同步更新
inventory表中的对应字段,或者在触发器关联查询时获取最新的商品信息。