You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

SQL递归实现库存与订单动态计算:基于历史行数据

解决库存补货递归计算的SQL实现问题

字段说明

  • week_start:日期类型,每周周一(当年的周起始日)
  • delivery_time:配送所需时长(天数)
  • safety_stock:仓库最低维持库存值
  • stock:初始库存数量
  • order_amount:每次下单的固定数量
  • Needed:当周所需物料数量

订单规则

当前库存(stock) - 当周需求(Needed) 低于**安全库存(safety_stock)**时,下单order_amount数量的物料;下单后,该订单量需添加到配送到达对应的week_start行的stock字段中。

示例数据

周起始日配送时长安全库存库存下单量实际下单量当周需求
06-01-20251410820205
13-01-20251410320202
20-01-20251410212005

问题分析

尝试用递归CTE实现时遇到两个核心难点:

  1. 无法精准定位需要参考的历史行来判断是否下单
  2. 无法将下单量正确追加到对应到货周的库存中,且循环判断后续下单逻辑

初始代码仅实现了基础的周关联,未处理库存更新和下单逻辑的递归传递。

解决方案:递归CTE实现完整逻辑

以下是适配逻辑的递归CTE代码(以SQL Server语法为例,其他数据库可调整日期函数):

WITH WeeklyInventory AS (
    -- 基准CASE:处理第一周数据,计算剩余库存和是否下单
    SELECT 
        week_start,
        delivery_time,
        safety_stock,
        -- 第一周扣除需求后的库存
        stock - Needed AS remaining_stock,
        order_amount,
        -- 判断是否下单:剩余库存低于安全库存则下单order_amount,否则0
        CASE WHEN (stock - Needed) < safety_stock THEN order_amount ELSE 0 END AS actual_order,
        Needed,
        -- 计算到货周:当前周+配送时长(14天=2周)
        DATEADD(week, delivery_time / 7, week_start) AS delivery_week
    FROM original_table
    WHERE week_start = (SELECT MIN(week_start) FROM original_table)

    UNION ALL

    -- 递归CASE:逐周处理,累加之前的到货订单,计算当前库存和下单逻辑
    SELECT 
        ot.week_start,
        ot.delivery_time,
        ot.safety_stock,
        -- 当前初始库存 + 所有历史订单中本周到货的数量 - 当周需求
        ot.stock + COALESCE(SUM(wi_delivery.actual_order), 0) - ot.Needed AS remaining_stock,
        ot.order_amount,
        -- 判断是否下单:剩余库存低于安全库存则下单
        CASE WHEN (ot.stock + COALESCE(SUM(wi_delivery.actual_order), 0) - ot.Needed) < ot.safety_stock 
             THEN ot.order_amount 
             ELSE 0 
        END AS actual_order,
        ot.Needed,
        DATEADD(week, ot.delivery_time / 7, ot.week_start) AS delivery_week
    FROM original_table ot
    INNER JOIN WeeklyInventory wi 
        ON ot.week_start = DATEADD(week, 1, wi.week_start)
    -- 关联所有到货周等于当前周的历史订单
    LEFT JOIN WeeklyInventory wi_delivery 
        ON wi_delivery.delivery_week = ot.week_start
    WHERE ot.week_start > (SELECT MIN(week_start) FROM original_table)
    GROUP BY ot.week_start, ot.delivery_time, ot.safety_stock, ot.stock, ot.order_amount, ot.Needed
)
-- 最终输出:包含所有周的计算结果,可按需调整字段
SELECT 
    week_start AS 周起始日,
    delivery_time AS 配送时长,
    safety_stock AS 安全库存,
    -- 显示当前周初始库存(含到货)
    stock + COALESCE((SELECT SUM(actual_order) FROM WeeklyInventory WHERE delivery_week = wi.week_start), 0) AS 当前库存,
    order_amount AS 下单量,
    actual_order AS 实际下单量,
    Needed AS 当周需求,
    remaining_stock AS 当周剩余库存,
    delivery_week AS 到货周
FROM WeeklyInventory wi
ORDER BY week_start;

代码说明

  1. 基准CASE:处理第一周数据,直接计算扣除需求后的剩余库存,判断是否需要下单,并计算该订单的到货周。
  2. 递归CASE
    • 逐周关联上一周的计算结果,确保按时间顺序处理
    • 通过LEFT JOIN关联所有历史订单中到货周等于当前周的记录,累加这些订单量到当前库存中
    • 重新计算当前库存扣除需求后的剩余量,判断是否需要下单
  3. 最终输出:展示每一周的初始库存(含到货)、实际下单量、剩余库存等关键数据,便于验证逻辑。

注意事项

  • 若配送时长不是7的整数倍,需调整DATEADD的计算逻辑(例如按天计算后取最近的周一)
  • 不同数据库的日期函数语法不同:MySQL用DATE_ADD,PostgreSQL用WEEKINTERVAL,需自行适配
  • 若存在多笔订单同时到货的情况,SUM(wi.actual_order)会自动累加所有符合条件的订单量

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

火山引擎 最新活动