根据前一行其他列的条件在 SQL 中动态填充值的最佳方法是什么?

问题描述 投票:0回答:1

这是我通常会在 python 中解决的问题,但想看看是否可以在 SQL 中有效地完成。

我有一个示例预测销售数据集,如下所示:

项目 位置_id 预测 周_开始 包装尺寸 行号
绿色铅笔 1234 0.82 12/3/23 6 1
绿色铅笔 1234 0.82 12/10/23 6 2
绿色铅笔 1234 0.82 12/17/23 6 3
绿色铅笔 1234 1.23 12/24/23 6 4
绿色铅笔 1234 1.23 12/31/23 6 5
绿色铅笔 1234 1.23 1/7/24 6 6
蓝色标记 999 4.31 12/3/23 6 1
蓝色标记 999 6.47 12/10/23 6 2
蓝色标记 999 6.47 12/17/23 6 3
蓝色标记 999 6.47 12/24/23 6 4
蓝色标记 999 6.47 12/31/23 6 5
蓝色标记 999 6.47 1/7/24 6 6

该数据是未来6周不同商品进入不同商店的预测销售量。行号已添加到每个项目/位置/周。

pack_size
列是需要库存时发送到商店的单位数量。

目标是创建两列

units_to_store
week_end_inventory
来确定何时应根据预测销量向商店发送一包商品。理想的最终状态数据集如下(仅适用于 green_pencil,但希望每个项目/商店组合都有它):

项目 位置_id 预测 周_开始 包装尺寸 行号 商店单位 周末库存
绿色铅笔 1234 1.43 12/3/23 6 1 6 4.57
绿色铅笔 1234 2.67 12/10/23 6 2 0 1.9
绿色铅笔 1234 0.82 12/17/23 6 3 0 1.08
绿色铅笔 1234 1.23 12/24/23 6 4 6 -0.15
绿色铅笔 1234 1.23 12/31/23 6 5 0 4.77
绿色铅笔 1234 1.23 1/7/24 6 6 0 3.54

第一周始终以

pack_size
项目开始,在本例中为 6 个单位。然后,目标是获取预测销售额并获得运行总和,直到该数字低于 0,此时应将新包装发送到商店,并且运行总和以
pack_size
重新开始。第一周的
week_end_inventory
将是
pack_size
-
forecast
,然后将在接下来的行/周中减去
forecast
,直到它低于 0,并且该过程将重新开始。

做到这一点的最佳方法是什么?我尝试过使用

lag
函数,但在需要动态填充值时遇到了麻烦。

sql mysql postgresql presto trino
1个回答
0
投票

以下假设是 MySQL(但请注意,“row_number”列会导致问题,因此有必要对该列使用反引号。这只是部分解决方案,但目前已经没有时间了。

CREATE TABLE mytable (
      item VARCHAR(200)
    , location_id INTEGER
    , forecast DECIMAL(10, 2)
    , week_begin DATE
    , pack_size INTEGER
    , `row_number` INTEGER
    );
INSERT INTO mytable (item, location_id, forecast, week_begin, pack_size, `row_number`) 
VALUES 
('green_pencil', 1234, 0.82, STR_TO_DATE('12/3/23', '%m/%d/%y'), 6, 1),
('green_pencil', 1234, 0.82, STR_TO_DATE('12/10/23', '%m/%d/%y'), 6, 2),
('green_pencil', 1234, 0.82, STR_TO_DATE('12/17/23', '%m/%d/%y'), 6, 3),
('green_pencil', 1234, 1.23, STR_TO_DATE('12/24/23', '%m/%d/%y'), 6, 4),
('green_pencil', 1234, 1.23, STR_TO_DATE('12/31/23', '%m/%d/%y'), 6, 5),
('green_pencil', 1234, 1.23, STR_TO_DATE('1/7/24', '%m/%d/%y'), 6, 6),
('blue_marker', 999, 4.31, STR_TO_DATE('12/3/23', '%m/%d/%y'), 6, 1),
('blue_marker', 999, 6.47, STR_TO_DATE('12/10/23', '%m/%d/%y'), 6, 2),
('blue_marker', 999, 6.47, STR_TO_DATE('12/17/23', '%m/%d/%y'), 6, 3),
('blue_marker', 999, 6.47, STR_TO_DATE('12/24/23', '%m/%d/%y'), 6, 4),
('blue_marker', 999, 6.47, STR_TO_DATE('12/31/23', '%m/%d/%y'), 6, 5),
('blue_marker', 999, 6.47, STR_TO_DATE('1/7/24', '%m/%d/%y'), 6, 6);


Records: 12  Duplicates: 0  Warnings: 0
SELECT 
      item
    , location_id
    , forecast
    , week_begin
    , pack_size
    , `row_number`
    , CASE 
            WHEN LAG(pack_size, 1, pack_size) OVER (PARTITION BY item, location_id ORDER BY week_begin, `row_number`) - forecast >= 0 
            THEN LAG(pack_size, 1, pack_size) OVER (PARTITION BY item, location_id ORDER BY week_begin, `row_number`) - forecast 
            ELSE pack_size - forecast 
        END AS units_to_store
    , CASE 
            WHEN LAG(pack_size, 1, pack_size) OVER (PARTITION BY item, location_id ORDER BY week_begin, `row_number`) - forecast < 0 
            THEN 0 
            ELSE LAG(pack_size, 1, pack_size) OVER (PARTITION BY item, location_id ORDER BY week_begin, `row_number`) - forecast 
        END AS week_end_inventory 
FROM mytable;

项目 位置_id 预测 周_开始 包装尺寸 行号 商店单位 周末库存
蓝色标记 999 4.31 2023-12-03 6 1 1.69 1.69
蓝色标记 999 6.47 2023-12-10 6 2 -0.47 0.00
蓝色标记 999 6.47 2023-12-17 6 3 -0.47 0.00
蓝色标记 999 6.47 2023-12-24 6 4 -0.47 0.00
蓝色标记 999 6.47 2023-12-31 6 5 -0.47 0.00
蓝色标记 999 6.47 2024-01-07 6 6 -0.47 0.00
绿色铅笔 1234 0.82 2023-12-03 6 1 5.18 5.18
绿色铅笔 1234 0.82 2023-12-10 6 2 5.18 5.18
绿色铅笔 1234 0.82 2023-12-17 6 3 5.18 5.18
绿色铅笔 1234 1.23 2023-12-24 6 4 4.77 4.77
绿色铅笔 1234 1.23 2023-12-31 6 5 4.77 4.77
绿色铅笔 1234 1.23 2024-01-07 6 6 4.77 4.77

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.