[英]SQL: Get all relationships recursively with condition
我们假设我们有以下两个表:
主表
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上的问题所以请原谅我糟糕的文本格式。
如果您将条目限制为pivot
以便primary < secondary
可以避免重复。 这是前4个级别的第一个传球。 由于模式是可预测的,因此应该可以有一个循环,它为循环中的每个增加级别构建查询字符串,然后动态地执行它。 它会在第一个查询返回行时退出。
-- 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
这是Sql Server 2008 R2的改进答案,希望您能够适应MySQL。 它会递归到任何深度。 最后是一个带有列tuple
的表(例如'1'或'1-2'或'1-2-3'), number
(元组中所有id
的数值之和)和lvl
中的lvl
。 然后,您可以选择具有最低级别的行。 我喜欢短名称,以避免脂肪手指错误,所以使用pri
为primary
, 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
- 只有在构建结果集时才需要它。
tuple sec number lvl
1-2-3 3 12 2
2-3-4 4 12 2
1-2-3-4 4 17 3
最初我使用了Sql Server公用表表达式(CTE),然后将其调整为在循环(如上所述)中运行,这更通用。 这段代码附有兴趣,因为我发现它很容易玩。
with summary as (
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
union all
select s.tuple + '-' + cast(p.sec as varchar(max)) as tuple,
p.sec, s.number + m.number as number, 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
)
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.