MySQL 商品拉链表 完整最终版(配备了全套存储过程)

此文定制了MySQL 专用 + 商品业务字段 的拉链表全套方案,包含:建表、初始化、每日增量、查询、维护脚本,完全贴合电商商品业务,直接复制到你的 MySQL 即可运行。

一、业务说明(商品场景)

  • 表用途:记录商品价格、上下架状态、分类、品牌等变化历史
  • 适用:商品信息偶尔变更、需要历史回溯
  • 拉链规则:
    • start_date:记录生效日期(包含)
    • end_date:记录失效日期(不包含)
    • end_date = '9999-12-31' = 当前最新有效数据
  • 执行频率:每日凌晨执行一次

二、1. 建表语句(MySQL 正式表)

复制代码
-- 创建数据仓库库(若无则新建)
CREATE DATABASE IF NOT EXISTS dw;
USE dw;

-- 商品维度拉链表
DROP TABLE IF EXISTS dw_goods_zip;
CREATE TABLE dw_goods_zip (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增主键',
    goods_id VARCHAR(64) NOT NULL COMMENT '商品ID(业务唯一键)',
    goods_name VARCHAR(255) NOT NULL COMMENT '商品名称',
    category_id VARCHAR(64) COMMENT '商品分类ID',
    category_name VARCHAR(100) COMMENT '商品分类名称',
    brand_id VARCHAR(64) COMMENT '品牌ID',
    brand_name VARCHAR(100) COMMENT '品牌名称',
    sale_price DECIMAL(18,2) COMMENT '销售价',
    market_price DECIMAL(18,2) COMMENT '市场价',
    goods_status TINYINT COMMENT '商品状态 1=上架 2=下架 3=删除',
    stock_num INT COMMENT '库存数量',
    start_date DATE NOT NULL COMMENT '生效日期',
    end_date DATE NOT NULL COMMENT '失效日期',
    is_current TINYINT NOT NULL COMMENT '1=当前有效 0=已失效',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '入库时间',
    PRIMARY KEY (id),
    UNIQUE KEY uk_goods_start (goods_id, start_date),
    KEY idx_is_current (is_current),
    KEY idx_date_range (start_date, end_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品维度拉链表';

三、2. 首次全量初始化脚本(基线数据)

复制代码
USE dw;

-- 清空历史(首次执行)
TRUNCATE TABLE dw_goods_zip;

-- 全量导入商品基线数据
-- 源表请替换成你的业务商品表:例如 ods.ods_goods_full
INSERT INTO dw_goods_zip (
    goods_id, goods_name, category_id, category_name,
    brand_id, brand_name, sale_price, market_price,
    goods_status, stock_num, start_date, end_date, is_current
)
SELECT
    goods_id,
    goods_name,
    category_id,
    category_name,
    brand_id,
    brand_name,
    sale_price,
    market_price,
    goods_status,
    stock_num,
    '2026-01-01' AS start_date,  -- 统一基线日期
    '9999-12-31' AS end_date,    -- 永久有效
    1 AS is_current
FROM ods.ods_goods_full;  -- 你的业务商品全量表

四、3. 每日增量更新脚本(核心 ⭐ 直接定时执行)

使用说明

  • @biz_dt:业务日期 = 前一天(例如今天 4.02,biz_dt = 4.01)

  • 脚本作用:关闭旧记录 + 插入新记录

  • 可直接放在定时任务 / 调度平台执行

    USE dw;

    -- ================= 变量配置 =================
    SET @biz_dt = '2026-04-01'; -- 前一天日期(每日修改)
    SET @new_start_date = @biz_dt + 1; -- 新记录生效日 = T日
    SET @current_end = '9999-12-31'; -- 永久有效

    -- 1. 创建当日变更增量临时表
    DROP TEMPORARY TABLE IF EXISTS tmp_goods_delta;
    CREATE TEMPORARY TABLE tmp_goods_delta (
    goods_id VARCHAR(64) PRIMARY KEY,
    goods_name VARCHAR(255),
    category_id VARCHAR(64),
    category_name VARCHAR(100),
    brand_id VARCHAR(64),
    brand_name VARCHAR(100),
    sale_price DECIMAL(18,2),
    market_price DECIMAL(18,2),
    goods_status TINYINT,
    stock_num INT
    );

    -- 2. 插入【前一天变更/新增】的商品数据
    INSERT INTO tmp_goods_delta
    SELECT
    goods_id, goods_name, category_id, category_name,
    brand_id, brand_name, sale_price, market_price,
    goods_status, stock_num
    FROM ods.ods_goods_inc
    WHERE dt = @biz_dt; -- 增量表按日期分区

    -- 3. 开启事务(保证数据原子性)
    START TRANSACTION;

    -- 4. 关闭旧的有效记录(更新失效日期)
    UPDATE dw_goods_zip
    SET end_date = @biz_dt,
    is_current = 0
    WHERE is_current = 1
    AND goods_id IN (SELECT goods_id FROM tmp_goods_delta);

    -- 5. 插入新的有效记录
    INSERT INTO dw_goods_zip (
    goods_id, goods_name, category_id, category_name,
    brand_id, brand_name, sale_price, market_price,
    goods_status, stock_num, start_date, end_date, is_current
    )
    SELECT
    goods_id, goods_name, category_id, category_name,
    brand_id, brand_name, sale_price, market_price,
    goods_status, stock_num,
    @new_start_date,
    @current_end,
    1
    FROM tmp_goods_delta;

    -- 6. 提交事务
    COMMIT;


五、4. 最常用查询脚本(直接复制使用)

① 查询当前所有有效商品(最新状态)

复制代码
SELECT * FROM dw_goods_zip WHERE is_current = 1;

② 回溯历史:查询某一天的商品快照

复制代码
SELECT *
FROM dw_goods_zip
WHERE start_date <= '2026-03-15'
  AND end_date   > '2026-03-15';

③ 查看单个商品完整变更历史

复制代码
SELECT *
FROM dw_goods_zip
WHERE goods_id = 'G20260001'
ORDER BY start_date;

④ 统计商品变更次数

复制代码
SELECT goods_id, goods_name, COUNT(*) AS change_times
FROM dw_goods_zip
GROUP BY goods_id, goods_name
ORDER BY change_times DESC;

六、5. MySQL 拉链表维护规范(必看)

  1. 禁止删除 / 修改历史记录 只允许:新增记录 + 更新end_date关闭旧记录
  2. 索引已建好保证历史查询速度,无需额外加索引
  3. 数据膨胀处理 超过 1 年的失效数据可归档到 dw_goods_zip_hist
  4. 事务必须开启MySQL 下用事务保证拉链不丢数据、不乱序
  5. 源表要求 业务库必须有:update_timedt 日期分区,用于抽取增量

MySQL 商品拉链表【存储过程终极版】(某商城生产环境)

全自动、传参即用、事务兜底、适配商品业务,可直接定时调用。

一、前置基础表(复用之前标准商品拉链表)

复制代码
CREATE DATABASE IF NOT EXISTS dw;
USE dw;

DROP TABLE IF EXISTS dw_goods_zip;
CREATE TABLE dw_goods_zip (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增主键',
    goods_id VARCHAR(64) NOT NULL COMMENT '商品ID',
    goods_name VARCHAR(255) NOT NULL COMMENT '商品名称',
    category_id VARCHAR(64) COMMENT '分类ID',
    category_name VARCHAR(100) COMMENT '分类名称',
    brand_id VARCHAR(64) COMMENT '品牌ID',
    brand_name VARCHAR(100) COMMENT '品牌名称',
    sale_price DECIMAL(18,2) COMMENT '售价',
    market_price DECIMAL(18,2) COMMENT '市场价',
    goods_status TINYINT COMMENT '1上架2下架3删除',
    stock_num INT COMMENT '库存',
    start_date DATE NOT NULL COMMENT '生效日',
    end_date DATE NOT NULL COMMENT '失效日',
    is_current TINYINT NOT NULL COMMENT '1当前有效0历史',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '入仓时间',
    PRIMARY KEY (id),
    UNIQUE KEY uk_goods_start (goods_id,start_date),
    KEY idx_current (is_current),
    KEY idx_dt_range (start_date,end_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品信息拉链表';

二、创建全自动拉链存储过程

逻辑:传入业务日期→自动取增量→关闭旧数据→插新数据→事务保证原子性

复制代码
USE dw;
DROP PROCEDURE IF EXISTS p_goods_zip_refresh;

DELIMITER //
CREATE PROCEDURE p_goods_zip_refresh(IN p_biz_dt DATE)
BEGIN
    -- 定义变量
    DECLARE v_new_start DATE;
    DECLARE v_max_end DATE DEFAULT '9999-12-31';
    
    -- 新记录生效日 = 业务日+1
    SET v_new_start = DATE_ADD(p_biz_dt,INTERVAL 1 DAY);

    -- 临时增量表(会话级临时表)
    DROP TEMPORARY TABLE IF EXISTS tmp_goods_delta;
    CREATE TEMPORARY TABLE tmp_goods_delta (
        goods_id VARCHAR(64) PRIMARY KEY,
        goods_name VARCHAR(255),
        category_id VARCHAR(64),
        category_name VARCHAR(100),
        brand_id VARCHAR(64),
        brand_name VARCHAR(100),
        sale_price DECIMAL(18,2),
        market_price DECIMAL(18,2),
        goods_status TINYINT,
        stock_num INT
    ) ENGINE=InnoDB;

    -- 1. 加载当日变更增量(替换成你真实增量表 ods.ods_goods_inc)
    INSERT INTO tmp_goods_delta
    SELECT goods_id,goods_name,category_id,category_name,
           brand_id,brand_name,sale_price,market_price,
           goods_status,stock_num
    FROM ods.ods_goods_inc
    WHERE dt = p_biz_dt;

    -- 无增量直接退出
    IF NOT EXISTS (SELECT 1 FROM tmp_goods_delta) THEN
        SELECT CONCAT(p_biz_dt,' 无商品变更数据,流程结束') AS result;
        LEAVE proc_end;
    END IF;

    -- 2. 事务执行拉链闭环
    START TRANSACTION;
        -- 关闭旧有效记录:失效日改为业务日,置为历史
        UPDATE dw_goods_zip
        SET end_date = p_biz_dt, is_current = 0
        WHERE is_current = 1
          AND goods_id IN (SELECT goods_id FROM tmp_goods_delta);

        -- 插入新版当前有效记录
        INSERT INTO dw_goods_zip
        (goods_id,goods_name,category_id,category_name,
         brand_id,brand_name,sale_price,market_price,
         goods_status,stock_num,start_date,end_date,is_current)
        SELECT goods_id,goods_name,category_id,category_name,
               brand_id,brand_name,sale_price,market_price,
               goods_status,stock_num,v_new_start,v_max_end,1
        FROM tmp_goods_delta;
    COMMIT;

    SELECT CONCAT('执行成功!业务日期:',p_biz_dt,' 新增生效日:',v_new_start) AS result;

proc_end:
    DROP TEMPORARY TABLE IF EXISTS tmp_goods_delta;
END //
DELIMITER ;

三、首次全量初始化存储过程(基线打底)

复制代码
USE dw;
DROP PROCEDURE IF EXISTS p_goods_zip_init;

DELIMITER //
CREATE PROCEDURE p_goods_zip_init(IN p_start_dt DATE)
BEGIN
    TRUNCATE TABLE dw_goods_zip;

    INSERT INTO dw_goods_zip
    (goods_id,goods_name,category_id,category_name,
     brand_id,brand_name,sale_price,market_price,
     goods_status,stock_num,start_date,end_date,is_current)
    SELECT goods_id,goods_name,category_id,category_name,
           brand_id,brand_name,sale_price,market_price,
           goods_status,stock_num,p_start_dt,'9999-12-31',1
    FROM ods.ods_goods_full; -- 你的商品全量基线表

    SELECT CONCAT('初始化完成,基线起始日期:',p_start_dt) AS init_result;
END //
DELIMITER ;

四、调用方式(超简单)

1、第一次打底初始化

复制代码
-- 统一基线开始日期,比如2026-01-01
CALL dw.p_goods_zip_init('2026-01-01');

2、每日定时调度(只传前一天日期)

复制代码
-- 例:跑4月2日任务,传4月1日
CALL dw.p_goods_zip_refresh('2026-04-01');

五、常用查询(直接配套使用)

复制代码
-- 1.查当前最新商品全量
SELECT * FROM dw_goods_zip WHERE is_current=1;

-- 2.回溯某天快照
SELECT * FROM dw_goods_zip
WHERE start_date <= '2026-03-20' AND end_date > '2026-03-20';

-- 3.单商品全变更轨迹
SELECT * FROM dw_goods_zip WHERE goods_id='G001' ORDER BY start_date;

六、运维 & 定时建议

  1. 定时任务 :MySQL 事件 / CRON / 调度平台,每日凌晨执行 CALL p_goods_zip_refresh(前一日日期)
  2. 严格禁止手动 update/delete 历史拉链数据
  3. 长期数据可归档:把 end_date < 'xxxx-xx-xx' 的历史记录迁移到归档表
  4. 所有增量依赖 ods.ods_goods_inc 按 dt 分区,确保能抓到每日变更
相关推荐
admin and root3 小时前
从资产收集FUZZ接口到SQL注入案例
网络·数据库·sql·安全·web安全·渗透测试·log4j
我真会写代码3 小时前
MySQL关键词全面总结(含用法+避坑指南)
数据库·mysql·索引
rainy雨3 小时前
精益数据分析系统功能拆解:如何用精益数据分析解决指标虚高难题与初创期验证场景
大数据·数据库·人工智能·信息可视化·数据挖掘·数据分析·精益工程
tycooncool3 小时前
QT数据库(三):QSqlQuery使用
数据库·qt·oracle
小陈工3 小时前
Python Web开发入门(十):数据库迁移与版本管理——让数据库变更可控可回滚
前端·数据库·人工智能·python·sql·云原生·架构
zzh0814 小时前
MySQL主从复制读写分离笔记
数据库·mysql
APIshop4 小时前
京东关键词搜索接口完全指南
java·开发语言·数据库
ZzzZZzzzZZZzzzz…4 小时前
MySQL备份还原方法1----xtrabackup
linux·运维·数据库·mysql·xtrabackup·物理备份
实泽有之,无泽虚之5 小时前
ORA-12518:Oracle 监听程序无法分发客户端连接原因及解决方法
数据库·oracle