mysql 存储过程

项目中出现需要写存储过程的任务。

需求描述:根据我们的仓库里面的库存,生成智能补货功能。

我先设计自动补货详情表和汇总表,详情表是以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

ep.id, epav.id, ep.mer_id,

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;

#######################################################

相关推荐
老虎06272 小时前
Netty[ NIO 核心速成 ] ---- NIO三大组件(Channel & Buffer&selector)
java·github·nio
Oueii2 小时前
如何为开源Python项目做贡献?
jvm·数据库·python
小王不爱笑1322 小时前
Java 异常全解析:从原理到实战,搞定异常处理
java·开发语言
人工智能AI技术2 小时前
Spring Boot 3.5正式普及!Java虚拟线程+GraalVM原生镜像,启动仅0.3秒
java
代码派2 小时前
免费本地部署的数据库 DevOps 工具,能覆盖多少日常工作场景?以 NineData 社区版为例
运维·数据库·database·devops·数据库管理工具·数据管理·sql工具
2401_891482172 小时前
Python Web爬虫入门:使用Requests和BeautifulSoup
jvm·数据库·python
没有bug.的程序员2 小时前
撕裂微服务网关的认证风暴:Spring Security 6.1 与 JWT 物理级免登架构大重构
java·spring·微服务·架构·security·jwt
小王不爱笑1322 小时前
Java Set 集合全家桶:HashSet、LinkedHashSet、TreeSet 详解与实战
java·开发语言
杨过姑父2 小时前
java 面试,jvm笔记
java·jvm·面试