需要 SQL 来选择行,直到列的总和达到最后一行不会完全消耗值的值

Posted

技术标签:

【中文标题】需要 SQL 来选择行,直到列的总和达到最后一行不会完全消耗值的值【英文标题】:Need SQL for selecting rows until sum of a column reach a value where the last row will not consume value in full 【发布时间】:2019-12-13 10:08:20 【问题描述】:

您好,可能有许多类似的实现,但我在此处的其他线程中找不到一件事。所以一个新的qs。

表格包含两列。 BOX_ID 和 No_of_Chocolates。 行:

BOX_ID, No_of_Chocolates
1, 10
2, 5
3, 15

期望 SQL 查询应该根据我需要的巧克力数量返回。

案例 1:需要巧克力 =5 SQL 结果应该是:

1, 5

(意思是,我可以从第一个盒子里得到 5 块巧克力)

案例 2:需要巧克力 =10 SQL 结果应该是:

1, 10

案例 3:需要巧克力 =13 SQL 结果应该是:

1, 10
2, 3

(意思是,我需要从 Box-1 中取出所有东西,从 Box-2 中取出 3)

案例 4:需要的巧克力 = 22 SQL 结果应该是:

1, 10
2, 5
3, 7

案例 5:需要的巧克力 = 35 SQL 结果应该是:

1, 10
2, 5
3, 15

(即使没有 35 块巧克力,它也应该提供所有可用的巧克力)

编辑: 对不起,如果结果被误解...结果不会用逗号连接。它将是两列。

【问题讨论】:

您是否还需要使用尽可能少的行来执行此操作?如果是这样,那么它可能真的是一个动态规划问题。 想知道如果只用sql查询就可以得到它,看起来应该有一个实现这个任务的函数,然后在where子句的sql查询中使用它。例如:函数(应该是流水线的)将返回它选择的行的 id,由 ',' 分隔,并且作为输入参数,您应该提供所需的巧克力数量。然后你可以在 where 子句中使用它:Select .... from where id in (function_call(35)), 当你需要 35 块巧克力时。 嗨蒂姆,感谢您的回复。不,我不想用尽可能少的行来做。我将拥有按日期排序的值的表格。 您好 Bartoz,如果结果被误解,对不起...结果不会用逗号连接。它将是两列。 【参考方案1】:

你可以做一个窗口求和并以此过滤:

select
    box_id,
    least(
        :wanted - total_no_of_chocolates, 
        no_of_chocolates
    ) no_of_chocolates
from (
    select
        t.*,
        coalesce(
                sum(no_of_chocolates) over(
                order by box_id
                rows between unbounded preceding and 1 preceding
            ),
            0
        ) total_no_of_chocolates
    from mytable t
) t
where total_no_of_chocolates < :wanted

wanted代表目标巧克力数量。

Demo on DB Fiddle

:wanted = 10 的结果:

BOX_ID | NO_OF_CHOCOLATES -----: | ---------------: 1 | 10

:wanted = 13 的结果:

BOX_ID | NO_OF_CHOCOLATES -----: | ---------------: 1 | 10 2 | 3

:wanted = 22 的结果:

BOX_ID | NO_OF_CHOCOLATES -----: | ---------------: 1 | 10 2 | 5 3 | 7

:wanted = 35 的结果:

BOX_ID | NO_OF_CHOCOLATES -----: | ---------------: 1 | 10 2 | 5 3 | 15

【讨论】:

【参考方案2】:

GMB 的解决方案是正确的。但我认为有一种更简单的方式来表达类似的逻辑。

我会使用累积和,但像这样:

select b.box_id,
       least(:needed - sum_upto_box, no_of_chocolates) as from_this_box
from (select b.*,
             sum(no_of_chocolates) over (order by box_id) - no_of_chocolates as sum_upto_box
      from boxes b
     ) b
where sum_upto_box < :needed 

【讨论】:

以上是关于需要 SQL 来选择行,直到列的总和达到最后一行不会完全消耗值的值的主要内容,如果未能解决你的问题,请参考以下文章

编辑数字直到达到总和值

要选择的 SQL 查询,直到 SUM(users_count) 达到 1000

怎样读取excel某一列的每一行内容

在excel里如何计算一列数字的总和?

选择运行总计,直到达到特定 SUM

如何获取MySQL行,直到某列的总和超过阈值?