从总行到其他多行的拆分值,直到总和达到总行的值

发布于 01-18 23:12 字数 2346 浏览 5 评论 0原文

DB-Fiddle

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_quantityexpected_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;

我不知道如何实现这一目标。
你有什么想法吗?

DB-Fiddle

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');

Expected Result

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

I want to split the received_inbound_quantity to each row of the expected_inbound_quantity until the total of the received_inbound_quantity is reached.

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;

I have no clue how to achieve this.
Do you have any idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

扎心 2025-01-25 23:12:42

我想出了以下内容:

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 code> 或 expected_inbound_date。避免值 < 0,我用过greatest

I came up with the following:

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

Here is a db fiddle.

The idea is to calculate the cumulative sum of rows preceding the current row as cum_sum and then to pick whatever is less: the sum of received_inbound_quantity minus the cum_sum or the expected_inbound_date. To avoid values < 0, I've used greatest.

养猫人 2025-01-25 23:12:42

关于答案,此问题解决此问题的另一种方法,该问题也可以在Redshift中工作:

db-fiddle

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;

With reference to the answer in this question an alternative way to solve the issue which is also working in redshift:

DB-Fiddle

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文