从 mysql table 中的单个列中找到等于给定总和的数字组合
find a combination of numbers that equal a given sum from a single column in mysql table
我有一个 MySQL table 包,其中包含字段 id, max_post
。 max_post 中的值包含
1,2,3,4,5,10,20,30,40,50,100,200,500,1000,2000
我想找到最合适的包裹。比如我输入230,那么应该
删除所有内容和 select 200 和 30 个包。我想使用 SQL 查询获得结果。
这是一个装箱问题的例子。基本上,解决它的唯一方法是显式。
您可以通过显式连接获取所有此类组合的列表:
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
将 "shorter" 列表放在第一位。如果你愿意,你可以添加一个limit
。
注意:这实际上是在 table 中的值之间创建四次笛卡尔积。随着 tables 大小的增长,执行时间也会增长。
满足您要求的替代方案 483
=> 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
tables,笛卡尔积搜索 可能 更快 (尽管没有解决上述情况) ,对于任何合理大小的任何东西,我希望相关的子查询更快。
对于 table 的 10 个值
- 笛卡尔积搜索数百种组合 (远远超过 10 choose 4
= 210
)
- 相关子查询搜索 40 个值 (10x4)
对于 table 的 100 个值
- 笛卡尔积搜索了数百万种组合 (远远超过 100 choose 4
= 3,921,225
)
- 相关子查询搜索 400 个值 (100x4)
这是 Gordon 查询的更正版本。主要是 Gordon 的查询缺少在可用值较小时加入空记录。它为 230 找到的最佳匹配是 200-20-5-4,因为最佳解决方案 200-30-null-null 甚至不在我们正在评估的集合中。这是因为 p3 实际上从未外连接到 200-30,因为 table 中存在值小于 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
来稍微优化,因此值本身已经高于所需总和的记录将立即被忽略。)
SQL fiddle: http://sqlfiddle.com/#!9/5f6d25/18.
我有一个 MySQL table 包,其中包含字段 id, max_post
。 max_post 中的值包含
1,2,3,4,5,10,20,30,40,50,100,200,500,1000,2000
我想找到最合适的包裹。比如我输入230,那么应该 删除所有内容和 select 200 和 30 个包。我想使用 SQL 查询获得结果。
这是一个装箱问题的例子。基本上,解决它的唯一方法是显式。
您可以通过显式连接获取所有此类组合的列表:
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
将 "shorter" 列表放在第一位。如果你愿意,你可以添加一个limit
。
注意:这实际上是在 table 中的值之间创建四次笛卡尔积。随着 tables 大小的增长,执行时间也会增长。
满足您要求的替代方案 483
=> 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
tables,笛卡尔积搜索 可能 更快 (尽管没有解决上述情况) ,对于任何合理大小的任何东西,我希望相关的子查询更快。
对于 table 的 10 个值
- 笛卡尔积搜索数百种组合 (远远超过 10 choose 4
= 210
)
- 相关子查询搜索 40 个值 (10x4)
对于 table 的 100 个值
- 笛卡尔积搜索了数百万种组合 (远远超过 100 choose 4
= 3,921,225
)
- 相关子查询搜索 400 个值 (100x4)
这是 Gordon 查询的更正版本。主要是 Gordon 的查询缺少在可用值较小时加入空记录。它为 230 找到的最佳匹配是 200-20-5-4,因为最佳解决方案 200-30-null-null 甚至不在我们正在评估的集合中。这是因为 p3 实际上从未外连接到 200-30,因为 table 中存在值小于 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
来稍微优化,因此值本身已经高于所需总和的记录将立即被忽略。)
SQL fiddle: http://sqlfiddle.com/#!9/5f6d25/18.