我有一个包含字段id, max_post
的MySQL表包。 max_post中的值包含
1,2,3,4,5,10,20,30,40,50,100,200,500,1000,2000
我想找到最适合的套餐。例如,我输入230,然后它应该 消除一切,选择200和30包。我想使用SQL查询获得结果。
答案 0 :(得分:1)
这是装箱问题的一个例子。基本上,解决它的唯一方法是明确的。
您可以通过显式连接获取所有此类组合的列表:
select p1.max_post, p2.max_post, p3.max_post, p4.max_post
from packages p1 left join
packages p2
on p1.max_post > p2.max_post left join
packages p3
on p2.max_post > p3.max_post left join
packages p4
on p3.max_post > p4.max_post
where (p1.max_post + coalesce(p2.max_post, 0) + coalesce(p3.max_post, 0) +
coalesce(p4.max_post, 0)
) = 230
order by (p2.max_post is null) desc,
(p3.max_post is null) desc,
(p4.max_post is null) desc
order by
首先放入“较短”列表。如果您愿意,可以添加limit
。
注意:这实际上是在表格中的值中创建了四次笛卡尔积。随着表的大小增加,执行的时间也会增加。
答案 1 :(得分:1)
以下是Gordon查询的更正版本。主要是当有较小的值可用时,Gordon的查询缺少加入空记录。它为230找到的最佳匹配是200-20-5-4,因为最佳解决方案200-30-null-null甚至不在我们正在评估的集合中。这是因为p3永远不会外连接到200-30,因为表中的值小于30的记录。 (对于外连接意味着当没有匹配时添加空记录。)
select
p1.max_post, p2.max_post, p3.max_post, p4.max_post
from packages p1
left join (select max_post from packages union all select null) p2
on (p1.max_post > p2.max_post or p2.max_post is null)
left join (select max_post from packages union all select null) p3
on (p2.max_post > p3.max_post or p3.max_post is null)
left join (select max_post from packages union all select null) p4
on (p3.max_post > p4.max_post or p4.max_post is null)
where p1.max_post + coalesce(p2.max_post, 0) + coalesce(p3.max_post, 0) + coalesce(p4.max_post, 0) <= 230
order by
p1.max_post + coalesce(p2.max_post, 0) + coalesce(p3.max_post, 0) + coalesce(p4.max_post, 0) desc,
(p2.max_post is null) desc,
(p3.max_post is null) desc,
(p4.max_post is null) desc
limit 1;
(可以通过向查询添加where max_post <= 230
来稍微优化一下,因此值本身已经高于所需总和的记录将立即被解除。)
答案 2 :(得分:0)
符合您声明的483
=&gt;的替代方案200,100,50,40
SELECT
target.max_post,
p1.id,
p1.max_post,
p2.id,
p2.max_post,
p3.id,
p3.max_post,
p4.id,
p4.max_post
FROM
(
SELECT 483 AS max_post
)
target
LEFT JOIN
packages p1
ON p1.id = (SELECT id
FROM packages
WHERE max_post <= target.max_post
ORDER BY max_post DESC
LIMIT 1
)
LEFT JOIN
packages p2
ON p2.id = (SELECT id
FROM packages
WHERE max_post <= target.max_post - p1.max_post
ORDER BY max_post DESC
LIMIT 1
)
LEFT JOIN
packages p3
ON p3.id = (SELECT id
FROM packages
WHERE max_post <= target.max_post - p1.max_post - p2.max_post
ORDER BY max_post DESC
LIMIT 1
)
LEFT JOIN
packages p4
ON p4.id = (SELECT id
FROM packages
WHERE max_post <= target.max_post - p1.max_post - p2.max_post - p3.max_post
ORDER BY max_post DESC
LIMIT 1
)
它使用重复的相关子查询。对于非常小的packages
表,笛卡尔积搜索可以更快(虽然不能解决上面提到的情况),对于我预期的任何合理大小的任何内容相关的子查询更快。
对于10个值的表格
- 笛卡尔积搜索了数百种组合(远远超过10 choose 4
= 210
)
- 相关子查询搜索40个值(10x4)
对于100个值的表格
- Cartessian产品搜索数百万种组合(远远超过100 choose 4
= 3,921,225
)
- 相关子查询搜索400个值(100x4)