You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL商品价格有效期计算:生成含生效/失效日期的价格表

实现商品价格有效期表的SQL解决方案

我有一张存储商品、价格及添加日期的表,表结构及数据如下:

CREATE TABLE item_prices (
    item_id         INT,
    item_name       VARCHAR(30),
    item_price      DECIMAL(12, 2),
    created_dttm    DATETIME
);

INSERT INTO item_prices(item_id, item_name, item_price, created_dttm) VALUES
(1, 'spoon', 10.20 , '2023-01-01 01:00:00'),
(1, 'spoon', 10.20 , '2023-01-08 01:35:00'),
(1, 'spoon', 10.35 , '2023-01-14 15:00:00'),
(2, 'table', 40.00 , '2023-01-01 01:00:00'),
(2, 'table', 40.00 , '2023-01-03 11:22:00'),
(2, 'table', 41.00 , '2023-01-10 08:28:22'),
(1, 'spoon', 10.35 , '2023-01-28 21:52:00'),
(1, 'spoon', 11.00 , '2023-02-15 16:36:00'),
(2, 'table', 41.00 , '2023-02-16 21:42:11'),
(2, 'table', 45.20 , '2023-02-19 20:25:25'),
(1, 'spoon',  9.00 , '2023-03-02 14:50:00'),
(1, 'spoon',  9.00 , '2023-03-06 16:36:00'),
(1, 'spoon',  8.50 , '2023-03-15 12:00:00'),
(2, 'table', 30    , '2023-03-05 10:10:10'),
(2, 'table', 30    , '2023-03-10 15:45:00');

需求

需要创建一张新表,包含以下字段:

  • item_id
  • item_name
  • item_price
  • valid_from_dt:价格生效日期(对应记录的created_dttm)
  • valid_to_dt:价格失效日期(同商品下一条记录的created_dttm减1天)

我的尝试

我尝试通过以下查询获取首次出现新价格的日期:

SELECT item_id, item_name, item_price, 
       MIN(created_dttm) as dt 
FROM item_prices
GROUP BY item_price, item_id, item_name

该查询能返回各价格首次出现的日期,但还需要进一步处理得到完整的有效期。

预期输出示例

item_iditem_nameitem_pricevalid_from_dtvalid_to_dt
1spoon10.202023-01-012023-01-13
1spoon10.352023-01-142023-02-14
1spoon11.002023-02-152023-03-01
1spoon9.002023-03-022023-03-14
1spoon8.502023-03-15至今
2table40.002023-01-012023-01-09
2table41.002023-01-102023-02-18
...............

完整SQL解决方案

1. 查询获取有效期数据

使用CTE和窗口函数实现需求:

WITH price_first_dates AS (
    SELECT 
        item_id,
        item_name,
        item_price,
        MIN(created_dttm) AS valid_from_dt
    FROM item_prices
    GROUP BY item_id, item_name, item_price
),
ordered_prices AS (
    SELECT 
        *,
        -- 获取同商品下一条价格的生效日期
        LEAD(valid_from_dt) OVER (PARTITION BY item_id, item_name ORDER BY valid_from_dt) AS next_valid_from
    FROM price_first_dates
)
SELECT 
    item_id,
    item_name,
    item_price,
    DATE(valid_from_dt) AS valid_from_dt, -- 提取日期部分,匹配预期格式
    CASE 
        WHEN next_valid_from IS NOT NULL THEN DATE(DATE_SUB(next_valid_from, INTERVAL 1 DAY))
        ELSE '至今'
    END AS valid_to_dt
FROM ordered_prices
ORDER BY item_id, valid_from_dt;

2. 创建新表

如果需要直接生成目标表,使用CREATE TABLE ... AS SELECT:

CREATE TABLE item_price_validity AS
WITH price_first_dates AS (
    SELECT 
        item_id,
        item_name,
        item_price,
        MIN(created_dttm) AS valid_from_dt
    FROM item_prices
    GROUP BY item_id, item_name, item_price
),
ordered_prices AS (
    SELECT 
        *,
        LEAD(valid_from_dt) OVER (PARTITION BY item_id, item_name ORDER BY valid_from_dt) AS next_valid_from
    FROM price_first_dates
)
SELECT 
    item_id,
    item_name,
    item_price,
    DATE(valid_from_dt) AS valid_from_dt,
    CASE 
        WHEN next_valid_from IS NOT NULL THEN DATE(DATE_SUB(next_valid_from, INTERVAL 1 DAY))
        ELSE '至今'
    END AS valid_to_dt
FROM ordered_prices
ORDER BY item_id, valid_from_dt;

逻辑说明

  • price_first_dates:分组获取每个商品每个价格的首次生效日期,延续原有的查询思路。
  • ordered_prices:通过LEAD()窗口函数,按商品分组、生效日期排序,获取下一个价格的生效时间。
  • 最终查询:将生效日期转为纯日期格式,计算失效日期(下一个生效日减1天),最后一条记录显示“至今”。

内容的提问来源于stack exchange,提问作者Oleg Romanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:56:07