将总计行的值拆分到其他多个行,直到总和达到总计行的值
Split value from a total row to multiple other rows until the sum reaches the value of the total row
CREATE TABLE inbound (
id SERIAL PRIMARY KEY,
campaign VARCHAR,
expected_inbound_date DATE,
expected_inbound_quantity DECIMAL,
received_inbound_quantity DECIMAL
);
INSERT INTO inbound
(campaign, expected_inbound_date, expected_inbound_quantity, received_inbound_quantity)
VALUES
('C001', '2022-05-03', '500', '0'),
('C001', '2022-05-03', '800', '0'),
('C001', '2022-05-03', '400', '0'),
('C001', '2022-05-03', '200', '0'),
('C001', NULL, '0', '700'),
('C002', '2022-08-20', '3000', '0'),
('C002', '2022-08-20', '5000', '0'),
('C002', '2022-08-20', '2800', '0'),
('C002', NULL, '0', '4000');
预期结果
campaign | expected_inbound_date | expected_inbound_quantity | split_received_inbound_quantity
---------|------------------------|-----------------------------|----------------------------------
C001 | 2022-05-03 | 200 | 200
C001 | 2022-05-03 | 400 | 400
C001 | 2022-05-03 | 500 | 100
C001 | 2022-05-03 | 800 | 0
C001 | | | 700
---------|------------------------|-----------------------------|----------------------------------
C002 | 2022-08-20 | 3.800 | 3.800
C002 | 2022-08-20 | 5.000 | 200
C002 | 2022-08-20 | 2.800 | 0
C002 | | | 4.000
我想将 received_inbound_quantity
拆分到 expected_inbound_quantity
的每一行,直到达到 received_inbound_quantity
的总数。
SELECT
i.campaign AS campaign,
i.expected_inbound_date AS expected_inbound_date,
i.expected_inbound_quantity AS expected_inbound_quantity,
i.received_inbound_quantity AS split_received_inbound_quantity
FROM inbound i
GROUP BY 1,2,3,4
ORDER BY 1,2,3,4;
我不知道如何做到这一点。
你有什么想法吗?
我得出以下结论:
select i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity, (
select greatest(
least(
i.expected_inbound_quantity,
(select sum(iii.received_inbound_quantity) from inbound iii where i.campaign = iii.campaign) -
(
select cum_sum
from (
select sum(ii.expected_inbound_quantity) over (partition by ii.campaign order by ii.expected_inbound_date, ii.expected_inbound_quantity, ii.received_inbound_quantity rows between unbounded preceding and 1 preceding) cum_sum, ii.campaign, ii.expected_inbound_date, ii.expected_inbound_quantity, ii.received_inbound_quantity
from inbound ii
) tmp
where (tmp.campaign, tmp.expected_inbound_date, tmp.expected_inbound_quantity, tmp.received_inbound_quantity) = (i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity)
)
),
0
)
) split
from inbound i
order by i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity
这里是db fiddle.
想法是计算当前行之前的行的累积总和为 cum_sum
,然后选择较小的:received_inbound_quantity
的总和减去 cum_sum
或expected_inbound_date
。为了避免值 < 0,我使用了 greatest
.
参考 中的答案,另一种解决问题的方法也适用于 redshift
:
SELECT
t1.campaign AS campaign,
t1.expected_inbound_date AS expected_inbound_date,
t1.expected_inbound_quantity AS expected_inbound_quantity,
t1.received_inbound_quantity AS received_inbound_quantity,
t1.quantity_accumulated AS quantity_accumulated,
t1.quantity_total AS quantity_total,
(CASE WHEN (t1.quantity_total - t1.quantity_accumulated) >=0
THEN t1.expected_inbound_quantity ELSE
(CASE WHEN (t1.expected_inbound_quantity + t1.quantity_total - t1.quantity_accumulated) >=0
THEN (t1.expected_inbound_quantity + t1.quantity_total - t1.quantity_accumulated)
ELSE 0 END)
END) AS split
FROM
(SELECT
i.campaign AS campaign,
i.expected_inbound_date AS expected_inbound_date,
i.expected_inbound_quantity AS expected_inbound_quantity,
i.received_inbound_quantity AS received_inbound_quantity,
SUM(i.expected_inbound_quantity) OVER (PARTITION BY i.campaign ORDER BY i.expected_inbound_date, i.expected_inbound_quantity ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS quantity_accumulated,
MAX(i.received_inbound_quantity) OVER (PARTITION BY i.campaign) AS quantity_total
FROM inbound i) t1
GROUP BY 1,2,3,4,5,6
ORDER BY 1,2,3,4,5,6;
CREATE TABLE inbound (
id SERIAL PRIMARY KEY,
campaign VARCHAR,
expected_inbound_date DATE,
expected_inbound_quantity DECIMAL,
received_inbound_quantity DECIMAL
);
INSERT INTO inbound
(campaign, expected_inbound_date, expected_inbound_quantity, received_inbound_quantity)
VALUES
('C001', '2022-05-03', '500', '0'),
('C001', '2022-05-03', '800', '0'),
('C001', '2022-05-03', '400', '0'),
('C001', '2022-05-03', '200', '0'),
('C001', NULL, '0', '700'),
('C002', '2022-08-20', '3000', '0'),
('C002', '2022-08-20', '5000', '0'),
('C002', '2022-08-20', '2800', '0'),
('C002', NULL, '0', '4000');
预期结果
campaign | expected_inbound_date | expected_inbound_quantity | split_received_inbound_quantity
---------|------------------------|-----------------------------|----------------------------------
C001 | 2022-05-03 | 200 | 200
C001 | 2022-05-03 | 400 | 400
C001 | 2022-05-03 | 500 | 100
C001 | 2022-05-03 | 800 | 0
C001 | | | 700
---------|------------------------|-----------------------------|----------------------------------
C002 | 2022-08-20 | 3.800 | 3.800
C002 | 2022-08-20 | 5.000 | 200
C002 | 2022-08-20 | 2.800 | 0
C002 | | | 4.000
我想将 received_inbound_quantity
拆分到 expected_inbound_quantity
的每一行,直到达到 received_inbound_quantity
的总数。
SELECT
i.campaign AS campaign,
i.expected_inbound_date AS expected_inbound_date,
i.expected_inbound_quantity AS expected_inbound_quantity,
i.received_inbound_quantity AS split_received_inbound_quantity
FROM inbound i
GROUP BY 1,2,3,4
ORDER BY 1,2,3,4;
我不知道如何做到这一点。
你有什么想法吗?
我得出以下结论:
select i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity, (
select greatest(
least(
i.expected_inbound_quantity,
(select sum(iii.received_inbound_quantity) from inbound iii where i.campaign = iii.campaign) -
(
select cum_sum
from (
select sum(ii.expected_inbound_quantity) over (partition by ii.campaign order by ii.expected_inbound_date, ii.expected_inbound_quantity, ii.received_inbound_quantity rows between unbounded preceding and 1 preceding) cum_sum, ii.campaign, ii.expected_inbound_date, ii.expected_inbound_quantity, ii.received_inbound_quantity
from inbound ii
) tmp
where (tmp.campaign, tmp.expected_inbound_date, tmp.expected_inbound_quantity, tmp.received_inbound_quantity) = (i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity)
)
),
0
)
) split
from inbound i
order by i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity
这里是db fiddle.
想法是计算当前行之前的行的累积总和为 cum_sum
,然后选择较小的:received_inbound_quantity
的总和减去 cum_sum
或expected_inbound_date
。为了避免值 < 0,我使用了 greatest
.
参考 redshift
:
SELECT
t1.campaign AS campaign,
t1.expected_inbound_date AS expected_inbound_date,
t1.expected_inbound_quantity AS expected_inbound_quantity,
t1.received_inbound_quantity AS received_inbound_quantity,
t1.quantity_accumulated AS quantity_accumulated,
t1.quantity_total AS quantity_total,
(CASE WHEN (t1.quantity_total - t1.quantity_accumulated) >=0
THEN t1.expected_inbound_quantity ELSE
(CASE WHEN (t1.expected_inbound_quantity + t1.quantity_total - t1.quantity_accumulated) >=0
THEN (t1.expected_inbound_quantity + t1.quantity_total - t1.quantity_accumulated)
ELSE 0 END)
END) AS split
FROM
(SELECT
i.campaign AS campaign,
i.expected_inbound_date AS expected_inbound_date,
i.expected_inbound_quantity AS expected_inbound_quantity,
i.received_inbound_quantity AS received_inbound_quantity,
SUM(i.expected_inbound_quantity) OVER (PARTITION BY i.campaign ORDER BY i.expected_inbound_date, i.expected_inbound_quantity ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS quantity_accumulated,
MAX(i.received_inbound_quantity) OVER (PARTITION BY i.campaign) AS quantity_total
FROM inbound i) t1
GROUP BY 1,2,3,4,5,6
ORDER BY 1,2,3,4,5,6;