项目中出现需要写存储过程的任务。
需求描述:根据我们的仓库里面的库存,生成智能补货功能。
我先设计自动补货详情表和汇总表,详情表是以sku维度进行汇总。
补充概念:spu是以商品id 为维度,sku 是商品的规格为维度。
实现结果:下面都是测试数据


##############新增表:自动补货汇总表和详情表 ###############
DROP TABLE IF EXISTS eb_automatic_summary;
CREATE TABLE IF NOT EXISTS eb_automatic_summary (
id INT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
total_stock INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '可售库存总数量',
total_stock_weight DECIMAL(12,3) NOT NULL DEFAULT 0.000 COMMENT '可售库存总克重(单位:g)',
total_suggest_replenish INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '建议补货总数量',
actual_replenish_num INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '实际申请补货库存数量',
actual_replenish_weight DECIMAL(12,3) NOT NULL DEFAULT 0.000 COMMENT '实际申请补货库存克重(单位:g)',
reference_date DATE NOT NULL COMMENT '统计日期(当天日期)',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id),
INDEX idx_reference_date (reference_date) COMMENT '统计日期索引,优化查询'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='自动补货汇总表';
DROP TABLE IF EXISTS eb_automatic_reference;
CREATE TABLE IF NOT EXISTS eb_automatic_reference (
id INT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
summary_id INT NOT NULL COMMENT '汇总表ID(关联eb_automatic_summary.id)',
product_id INT COMMENT '商品ID',
sku_id INT COMMENT 'SKU ID(对应eb_product_attr_value.id)',
mer_id INT NOT NULL DEFAULT '0' COMMENT '商户Id',
daily_sales INT UNSIGNED DEFAULT 0 COMMENT '日销量(近1天:仅昨天)',
weekly_sales INT UNSIGNED DEFAULT 0 COMMENT '周销量(近7天:昨天往前推6天)',
monthly_sales INT UNSIGNED DEFAULT 0 COMMENT '月销量(近30天:昨天往前推29天)',
stock INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '可售库存(取自eb_product_attr_value.stock)',
stock_weight DECIMAL(10,3) DEFAULT 0.000 COMMENT '可售库存重量(单位:g,取自eb_product_attr_value.weight)',
safety_stock_threshold INT UNSIGNED NOT NULL DEFAULT 5 COMMENT '安全库存阈值(取自eb_system_config)',
suggest_replenishment INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '建议补货数量(安全库存-当前库存,最小值0)',
actual_replenish_num INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '实际发起补货数量',
actual_replenish_weight DECIMAL(10,3) NOT NULL DEFAULT 0.000 COMMENT '实际发起补货克重(单位:g)',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '数据生成时间',
PRIMARY KEY (id),
INDEX idx_summary_id (summary_id) COMMENT '关联汇总表索引,优化联表查询',
INDEX idx_mer_id (mer_id) COMMENT '商户ID索引,优化商户维度查询'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='自动补货详情表';
###############存储过程############################
#########################汇总详情表#####################################
-- 删除旧存储过程(若存在)
DROP PROCEDURE IF EXISTS procedure_automatic_summary;
-- 设置分隔符
DELIMITER //
CREATE PROCEDURE procedure_automatic_summary(OUT out_summary_id INT)
BEGIN
-- 错误捕获处理
DECLARE sqlstate_code VARCHAR(5);
DECLARE errno_code INT;
DECLARE msg_text TEXT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
sqlstate_code = RETURNED_SQLSTATE,
errno_code = MYSQL_ERRNO,
msg_text = MESSAGE_TEXT;
SELECT '汇总表基础数据生成失败' AS `错误类型`,
sqlstate_code AS `SQL状态码`,
errno_code AS `错误编号`,
msg_text AS `错误详情`;
SET out_summary_id = -1; -- 异常时返回无效ID
END;
-- 插入汇总表基础数据(统计日期=当天,统计值默认0,后续由详情表计算后回写)
INSERT INTO eb_automatic_summary (
total_stock,
total_stock_weight,
total_suggest_replenish,
actual_replenish_num,
actual_replenish_weight,
reference_date
)
VALUES (
0, -- 可售库存总数量(后续回写)
0.000, -- 可售库存总克重(后续回写)
0, -- 建议补货总数量(后续回写)
0, -- 实际补货数量(默认0)
0.000, -- 实际补货克重(默认0)
CURDATE() -- 统计日期=当天日期
);
-- 获取新增汇总记录的ID(输出给详情表存储过程)
SET out_summary_id = LAST_INSERT_ID();
-- 输出执行结果
SELECT
CONCAT('汇总表基础数据生成成功!汇总ID:', out_summary_id, ',统计日期:', CURDATE()) AS `执行结果`,
out_summary_id AS `汇总表ID`,
CURDATE() AS `统计日期`;
END //
-- 恢复默认分隔符
DELIMITER ;
#########################详情表#####################################
DROP PROCEDURE IF EXISTS procedure_automatic_replenish;
DELIMITER //
CREATE PROCEDURE procedure_automatic_replenish(IN in_summary_id INT)
BEGIN
-- 变量声明(不变)
DECLARE base_date DATE; -- 基准日期:昨天
DECLARE week_start_date DATE; -- 周销量起始日期:昨天往前推6天
DECLARE month_start_date DATE; -- 月销量起始日期:昨天往前推29天
DECLARE safety_stock_val INT; -- 安全库存阈值
-- 错误捕获处理(不变)
DECLARE sqlstate_code VARCHAR(5);
DECLARE errno_code INT;
DECLARE msg_text TEXT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
sqlstate_code = RETURNED_SQLSTATE,
errno_code = MYSQL_ERRNO,
msg_text = MESSAGE_TEXT;
SELECT '详情表生成+汇总回写失败' AS `错误类型`,
sqlstate_code AS `SQL状态码`,
errno_code AS `错误编号`,
msg_text AS `错误详情`,
in_summary_id AS `关联汇总表ID`,
base_date AS `统计基准日期(昨天)`;
END;
-- 变量赋值(不变)
SET base_date = CURDATE() - INTERVAL 1 DAY;
SET week_start_date = DATE_SUB(base_date, INTERVAL 6 DAY);
SET month_start_date = DATE_SUB(base_date, INTERVAL 29 DAY);
-- 获取安全库存阈值(不变)
SELECT IFNULL(`value`, 5) INTO safety_stock_val
FROM eb_system_config
WHERE `status` = 0 AND name = 'safety_stock_threshold'
LIMIT 1;
-- 插入详情表数据(核心修改:CAST(epav.stock AS SIGNED) 转换无符号类型)
INSERT INTO eb_automatic_reference (
summary_id,
product_id,
sku_id,
mer_id,
daily_sales,
weekly_sales,
monthly_sales,
stock,
stock_weight,
safety_stock_threshold,
suggest_replenishment, -- 关键修改处
actual_replenish_num,
actual_replenish_weight
)
SELECT
in_summary_id,
ep.id AS product_id,
epav.id AS sku_id,
IFNULL(ep.mer_id, 0) AS mer_id,
COUNT(CASE WHEN esscd.data_date = base_date THEN 1 END) AS daily_sales,
COUNT(CASE WHEN esscd.data_date BETWEEN week_start_date AND base_date THEN 1 END) AS weekly_sales,
COUNT(CASE WHEN esscd.data_date BETWEEN month_start_date AND base_date THEN 1 END) AS monthly_sales,
epav.stock AS stock,
epav.weight AS stock_weight,
safety_stock_val AS safety_stock_threshold,
-- 核心修改:将 epav.stock 转为有符号整数再运算,避免负数超出无符号范围
GREATEST(safety_stock_val - CAST(epav.stock AS SIGNED), 0) AS suggest_replenishment,
0 AS actual_replenish_num,
0.000 AS actual_replenish_weight
FROM eb_product_attr_value epav
INNER JOIN eb_product ep ON ep.id = epav.product_id AND ep.is_del = 0
LEFT JOIN eb_statistics_sales_code_daily esscd
ON ep.id = esscd.product_id
AND epav.id = esscd.product_attr_value_id
AND esscd.is_del = 0
WHERE epav.is_del = 0
GROUP BY
epav.stock, epav.weight,
safety_stock_val;
-- 回写汇总表统计值(不变)
UPDATE eb_automatic_summary
SET
total_stock = (SELECT SUM(stock) FROM eb_automatic_reference WHERE summary_id = in_summary_id),
total_stock_weight = (SELECT SUM(stock * stock_weight) FROM eb_automatic_reference WHERE summary_id = in_summary_id),
total_suggest_replenish = (SELECT SUM(suggest_replenishment) FROM eb_automatic_reference WHERE summary_id = in_summary_id),
update_time = CURRENT_TIMESTAMP
WHERE id = in_summary_id;
-- 输出执行结果(不变)
SELECT
CONCAT('详情表生成+汇总回写完成!关联汇总ID:', in_summary_id) AS `执行结果`,
base_date AS `统计基准日期(昨天)`,
week_start_date AS `周销量统计起始日期`,
month_start_date AS `月销量统计起始日期`,
(SELECT SUM(stock) FROM eb_automatic_reference WHERE summary_id = in_summary_id) AS `可售库存总数量`,
(SELECT SUM(stock * stock_weight) FROM eb_automatic_reference WHERE summary_id = in_summary_id) AS `可售库存总克重(g)`,
in_summary_id AS `关联汇总表ID`;
END //
DELIMITER ;
#############################################################
定时任务######
SET GLOBAL event_scheduler = ON;
DROP EVENT IF EXISTS event_auto_update_replenish;
CREATE EVENT IF NOT EXISTS event_auto_update_replenish
ON SCHEDULE EVERY 1 DAY STARTS '2025-12-01 03:00:00'
ON COMPLETION PRESERVE
DO
BEGIN
DECLARE v_summary_id INT;
CALL procedure_automatic_summary(v_summary_id);
IF v_summary_id > 0 THEN
CALL procedure_automatic_replenish(v_summary_id);
END IF;
END;
################# 手动执行 #######################
-- 1. 先生成汇总表ID
SET @summary_id = 0;
CALL procedure_automatic_summary(@summary_id);
-- 2. 调用详情表存储过程(变量会自动计算)
CALL procedure_automatic_replenish(@summary_id);
-- 3. 查看详情表中销量统计是否基于变量日期
SELECT
*
FROM eb_automatic_reference
WHERE summary_id = @summary_id
LIMIT 5;
-- 检查定时任务状态
SELECT * FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event_auto_update_replenish';
###########################################################
-- 清空表数据 → 重新执行存储过程
TRUNCATE TABLE eb_automatic_reference;
TRUNCATE TABLE eb_automatic_summary;
-- 重新生成数据
CALL create_replenish_reference_table();
###########################################################
-- 1. 删除定时任务
DROP EVENT IF EXISTS event_auto_update_replenish;
-- 2. 删除存储过程
DROP PROCEDURE IF EXISTS procedure_automatic_replenish;
DROP PROCEDURE IF EXISTS procedure_automatic_summary;
-- 3. 删除目标表
DROP TABLE IF EXISTS eb_automatic_reference;
DROP TABLE IF EXISTS eb_automatic_summary;
#######################################################