SQL - 选择ID的子集,其中sum(A)< = X和sum(B)最大

时间:2014-01-21 16:09:37

标签: sql postgresql subset self-join

我有table1:

CREATE TABLE table1 (
    itemID INTEGER PRIMARY KEY,  
    cost INTEGER NOT NULL,
    income INTEGER NOT NULL  
);

我有MYMONEY金额。

我希望SQL为我提供最好的物品组合,我可以买卖,以便获得最大的收入(我在离开商店后卖掉物品)

换句话说: 从table1获取子集,其中此子集中cost的总和小于或等于MYMONEYincome的总和最高。

例如,如果我们有一个包含元组(1, 5, 10)(2, 3, 6)(3, 2, 5)MYMONEY=5子集的表,其中满足第一个条件的是{(1, 5, 10)}{(2, 3, 6), (3, 2, 5)}。第二个条件是第二个子集更好,因为此子集中income的总和为11,其中income的第一个子集总和为10.

关键是,这些子集可能具有各种功率。如果我对子集的功率有限制,我可以通过加入或交叉产生足够的时间并选择最佳行来轻松实现。
我可以使用一个计数器c,它说“现在让我们只看到那些功率等于c的子集”并使用带有交叉产品的解决方案,但我觉得它很慢而且很难看。

如果有很多“最佳”子集,它可能只提供其中任何一个或所有子集,这并不重要。

如果重要,我正在使用PostgreSQL和Java。

2 个答案:

答案 0 :(得分:3)

您应该使用the Knapsack algorithm。在sql中很难解决它,所以我建议你在客户端获取所有需要的数据然后计算。

答案 1 :(得分:2)

可以使用SQL完成:

with recursive calc as (
   select itemid as itemid, array[itemid] as id_list, cost, income
   from table1
   where cost <= 5
   union all
   select c.itemid, p.id_list||c.itemid, c.cost + p.cost, c.income + p.income
   from table1 as c
     join calc as p on p.itemid < c.itemid
   where c.cost + p.cost <= 5
)
select *
from calc
order by income desc;

但只是因为可以完成,并不一定意味着这样做是个好主意。
对于任何真实世界的表格,此查询都会有 可怕的 效果。

这是一个SQLFiddle:http://sqlfiddle.com/#!15/10455/1