SQL:使用条件递归获取所有关系

时间:2016-05-19 05:29:08

标签: mysql sql

我们假设我们有以下两个表:

主要表

id | number
1  | 5
2  | 3
3  | 4
4  | 5

数据透视表

primary | secondary
1       | 2
2       | 3
3       | 4

在数据透视表中,我定义了主表元素之间的多对多关系。

我们将目的地号码设置为10。 现在我希望以递归方式获得所有关系组合,但只有当所有相关元素的列“数”的总和小于所需数字“10”时才会得到。

首先,我们得到所有没有任何相关元素的元素:

1: 5
2: 3
3: 4
4: 5

因为没有“10”或更多的元素我想获得第一级关系。所以:

1-2: 8 // Sum of both elements
2-3: 7
3-4: 9

正如你所看到的,我也不希望组合2-1,因为我们已经有1-2。 没有“10”或更多的组合,所以进入下一个级别:

1-2-3: 12 // result because 12 is greater than 10
2-3-4: 12 // also a possible result

结果我想要所有必需的元素ID。 谢谢你的帮助。

PS:我刚接触stackoverflow上的问题所以请原谅我的错误文本格式。

2 个答案:

答案 0 :(得分:0)

如果您将条目限制为primary < secondary,以便-- Level 1 select * from t1_main t where number > 10 -- Level 2 select p.pri, p.sec, m1.number + m2.number from t1_pivot p inner join t1_main m1 on m1.id = p.pri inner join t1_main m2 on m2.id = p.sec where m1.number + m2.number > 10 -- Level 3 select p1.pri, p1.sec, p2.sec, m1.number + m2.number + m3.number from t1_pivot p1 inner join t1_pivot p2 on p1.sec = p2.pri inner join t1_main m1 on m1.id = p1.pri inner join t1_main m2 on m2.id = p1.sec inner join t1_main m3 on m3.id = p2.sec where m1.number + m2.number + m3.number > 10 -- Level 4 select p1.pri, p1.sec, p2.sec, p3.sec, m1.number + m2.number + m3.number + m4.number from t1_pivot p1 inner join t1_pivot p2 on p1.sec = p2.pri inner join t1_pivot p3 on p2.sec = p3.pri inner join t1_main m1 on m1.id = p1.pri inner join t1_main m2 on m2.id = p1.sec inner join t1_main m3 on m3.id = p2.sec inner join t1_main m4 on m4.id = p3.sec where m1.number + m2.number + m3.number + m4.number > 10 可以避免重复。这是前4个级别的第一个传球。由于模式是可预测的,因此应该可以有一个循环,它为循环中的每个增加级别构建查询字符串,然后动态地执行它。它会在第一个查询返回行时退出。

malloc

答案 1 :(得分:0)

这是Sql Server 2008 R2的改进答案,希望您能够适应MySQL。它会递归到任何深度。最后是一个包含tuple列的表格(例如&#39; 1&#39;或&#39; 1-2&#39;或&#39; 1-2-3&#39;),{{ 1}}(元组中所有number s的数值之和)和id中的级别。然后,您可以选择具有最低级别的行。 我喜欢短名称以避免胖手指错误,因此对lvl使用priprimary使用sec

secondary

这是结果集。忽略create table #summary ( tuple varchar(max), sec int, number int, lvl int ) delete #summary insert #summary( tuple, sec, number, lvl ) select cast(p.pri as varchar(max)) + '-' + cast(p.sec as varchar(max)) as tuple, p.sec, m1.number + m2.number as number, 1 as lvl from t1_pivot p inner join t1_main m1 on m1.id = p.pri inner join t1_main m2 on m2.id = p.sec declare @rows int = 1, @lvl int = 1 while @rows > 0 begin insert #summary( tuple, sec, number, lvl ) select s.tuple + '-' + cast(p.sec as varchar(max)) as tuple, p.sec, s.number + m.number as number, s.lvl + 1 as lvl from #summary s inner join t1_pivot p on p.pri = s.sec inner join t1_main m on m.id = p.sec where s.lvl = @lvl set @rows = @@rowcount print @rows set @lvl = @lvl + 1 end select * from ( select * from #summary union select cast(id as varchar(max)) as tuple, 0 as sec, number, 0 as lvl from t1_main ) x where x.number > 10 order by lvl, tuple - 仅在构建结果集时才需要它。

sec

最初我使用了Sql Server公用表表达式(CTE),然后将其调整为在循环中运行(如上所述),这是更通用的。这段代码是附加的,因为我发现它非常容易使用。

tuple       sec number  lvl
1-2-3       3   12      2
2-3-4       4   12      2
1-2-3-4     4   17      3