【问题标题】:SQL: Get all relationships recursively with conditionSQL:使用条件递归获取所有关系
【发布时间】:2016-05-19 15:49:32
【问题描述】:

假设我们有以下两个表:

主表

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 个可能的结果
  • 1-2-3-4 呢?
  • 好的,现在唯一可能的组合是1-2-3-4: 17(如果你的号码是15)。我做对了吗?
  • @Shaharyar 是的,你是对的 :)

标签: mysql sql


【解决方案1】:

如果您将条目限制为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

【讨论】:

  • 我会试试这个。谢谢你:)
  • 我决定选择这个解决方案。效果很好。再次感谢你:)
【解决方案2】:

这是对 Sql Server 2008 R2 的改进答案,希望您可以适应 MySQL。它将递归到任何深度。您以包含 tuple 列(例如 '1' 或 '1-2' 或 '1-2-3')、number (元组中所有 ids 的数值之和)的表结束) 和lvl 中的级别。然后,您可以选择具有最低级别的行。 我喜欢短名称以避免粗手指错误,所以使用pri 表示primarysec 表示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

【讨论】:

  • 我也会试试这个。非常感谢:)
猜你喜欢
  • 2020-11-26
  • 2018-03-30
  • 1970-01-01
  • 2014-03-28
  • 1970-01-01
  • 2012-11-23
  • 2013-05-15
  • 1970-01-01
  • 2021-12-27
相关资源
最近更新 更多