如何获得总计为特定值的行的随机组合?
How to get a random combination of rows that sum up to a specific value?
我的Table:
+--------+--------------------+
|item_id| value |
+--------+--------------------+
| 1 | 1 |
| 2 | 4 |
| 3 | 2 |
| 4 | 6 |
+--------+--------------------+
SQL 查询结果应该是什么:
项目的随机组合,总和为 10,不同项目的数量可变(在本例中为 2。)
+--------------+--------------------+-------------+
|item_id | amount | sum |
+--------------+--------------------+-------------+
|2 |2 |8 |
|3 |1 |2 |
+--------------+--------------------+-------------+
结果显示
您得到 2 次项目 2(它的值为 4,所以它的总和为 8)。
并且您获得了一次项目 3(其值为 2)
这个组合总和为 10。
这甚至可能吗,如果有其他可能性,它不应该总是相同的组合并且随机选择吗?
您可以使用 self-join:
获得所有此类组合
select t1.item_id, t2.item_id
from t t1 join
t t2
on t1.value + t2.value = 10;
这会将值放在列中而不是单独的行中。
假设你想要一个单一的随机组合,你可以这样做:
select
*
from (
select
a.item_id as item1,
x.n as amount1,
a.value * x.n as sum1,
b.item_id as item2,
y.n as amount2,
b.value * y.n as sum2,
rand() as r
from my_table a
join my_table b on b.item_id <> a.item_id
cross join (
select 1 as n union select 2 union select 3 union select 4
union select 5 union select 6 union select 7 union select 8
union select 9 union select 10) x
cross join (
select 1 as n union select 2 union select 3 union select 4
union select 5 union select 6 union select 7 union select 8
union select 9 union select 10) y
where a.value * x.n + b.value * y.n = 10
) z
order by r -- sorted randomly
limit 1 -- to get only one combination; remove to get them all
每次你运行这个查询它都会选择一个随机的[不同]解决方案。
创建您提到的 table 和数据(我曾经测试过)的脚本是:
create table my_table (
item_id int,
value int
);
insert into my_table (item_id, value) values (1, 1);
insert into my_table (item_id, value) values (2, 4);
insert into my_table (item_id, value) values (3, 2);
insert into my_table (item_id, value) values (4, 6);
2019 年 7 月 1 日编辑:根据要求,这是一个使用递归 CTE(通用 Table 表达式)的等效 [较短] 解决方案,自 MariaDB 以来可用10.2.2(见Recursive Common Table Expressions):
with recursive
val as (select 1 as n union all select n + 1 from val where n < 10)
select
*
from (
select
a.item_id as item1,
x.n as amount1,
a.value * x.n as sum1,
b.item_id as item2,
y.n as amount2,
b.value * y.n as sum2,
rand() as r
from my_table a
join my_table b on b.item_id <> a.item_id
cross join val x
cross join val y
where a.value * x.n + b.value * y.n = 10
) z
order by r -- sorted randomly
limit 1 -- to get only one combination; remove to get all 22 answers
如果您需要使用更大的数字,此解决方案的扩展性会更好。
我的Table:
+--------+--------------------+
|item_id| value |
+--------+--------------------+
| 1 | 1 |
| 2 | 4 |
| 3 | 2 |
| 4 | 6 |
+--------+--------------------+
SQL 查询结果应该是什么: 项目的随机组合,总和为 10,不同项目的数量可变(在本例中为 2。)
+--------------+--------------------+-------------+
|item_id | amount | sum |
+--------------+--------------------+-------------+
|2 |2 |8 |
|3 |1 |2 |
+--------------+--------------------+-------------+
结果显示
您得到 2 次项目 2(它的值为 4,所以它的总和为 8)。
并且您获得了一次项目 3(其值为 2)
这个组合总和为 10。
这甚至可能吗,如果有其他可能性,它不应该总是相同的组合并且随机选择吗?
您可以使用 self-join:
获得所有此类组合select t1.item_id, t2.item_id
from t t1 join
t t2
on t1.value + t2.value = 10;
这会将值放在列中而不是单独的行中。
假设你想要一个单一的随机组合,你可以这样做:
select
*
from (
select
a.item_id as item1,
x.n as amount1,
a.value * x.n as sum1,
b.item_id as item2,
y.n as amount2,
b.value * y.n as sum2,
rand() as r
from my_table a
join my_table b on b.item_id <> a.item_id
cross join (
select 1 as n union select 2 union select 3 union select 4
union select 5 union select 6 union select 7 union select 8
union select 9 union select 10) x
cross join (
select 1 as n union select 2 union select 3 union select 4
union select 5 union select 6 union select 7 union select 8
union select 9 union select 10) y
where a.value * x.n + b.value * y.n = 10
) z
order by r -- sorted randomly
limit 1 -- to get only one combination; remove to get them all
每次你运行这个查询它都会选择一个随机的[不同]解决方案。
创建您提到的 table 和数据(我曾经测试过)的脚本是:
create table my_table (
item_id int,
value int
);
insert into my_table (item_id, value) values (1, 1);
insert into my_table (item_id, value) values (2, 4);
insert into my_table (item_id, value) values (3, 2);
insert into my_table (item_id, value) values (4, 6);
2019 年 7 月 1 日编辑:根据要求,这是一个使用递归 CTE(通用 Table 表达式)的等效 [较短] 解决方案,自 MariaDB 以来可用10.2.2(见Recursive Common Table Expressions):
with recursive
val as (select 1 as n union all select n + 1 from val where n < 10)
select
*
from (
select
a.item_id as item1,
x.n as amount1,
a.value * x.n as sum1,
b.item_id as item2,
y.n as amount2,
b.value * y.n as sum2,
rand() as r
from my_table a
join my_table b on b.item_id <> a.item_id
cross join val x
cross join val y
where a.value * x.n + b.value * y.n = 10
) z
order by r -- sorted randomly
limit 1 -- to get only one combination; remove to get all 22 answers
如果您需要使用更大的数字,此解决方案的扩展性会更好。