【问题标题】:Tricky Recursive MySQL query棘手的递归 MySQL 查询
【发布时间】:2013-01-10 20:29:01
【问题描述】:

我有一个有 2 列的表,usersID 和它们的 siblingID

找到给定用户的所有兄弟姐妹的最佳方法是什么?

问题很复杂。这是一个例子。

用户 1 有 5 个兄弟姐妹(2,3,4,5,6)

表格是这样的

userID|siblingID
1     | 2
1     | 3
6     | 5
5     | 3
3     | 1
4     | 6

【问题讨论】:

  • 您使用的是什么数据库?我假设您正在寻找递归解决方案,因此 5、3 和 1 都是 6 的兄弟姐妹。

标签: mysql sql


【解决方案1】:

ANSI SQL:

with recursive tree (userid, siblingid) as
(
   select userid, 
          siblingid
   from users
   where userId = 1
   union all 
   select c.userid,
          c.siblingid
   from users c
     join tree p on p.userid c.siblingId
)
select *
from tree;

对于 Oracle 11.2 和 SQL Server - 他们显然没有仔细查看 ANSI 规范 - 您需要删除 recursive 关键字(根据标准这是强制性的)

【讨论】:

  • 感谢您的帮助!我忘了指定我使用的是 MySQL。这似乎不适用于 MySQL
  • @Jakobovski:正确。 MySQL 不支持任何现代 SQL 功能,如递归查询、窗口函数等。
  • 到底有没有用 MySQL 做这个,还是我需要在 PHP 的数据库之外做这个?
  • @Jakobovski:对于 MySQL,最好使用 PHP。
  • 如何处理循环?
【解决方案2】:

即使使用多个 SQL 语句,答案也比我想象的要困难得多。

您的问题的简单答案是:创建一个包含所有兄弟关系的表。然后你可以这样查询:

select siblingid
from @allsiblings sa
where sa.userid = 3   

一个音符。我使用 SQL Server 的语法,只是因为它恰好是最方便的数据库。我只使用 MySQL 中的功能,所以应该很容易翻译。

如何创建表@AllSiblings?好吧,继续添加不存在的兄弟对,直到不再添加。我们通过自连接获得对。

这里是代码(以前面的警告为准):

declare @allsiblings table (userid integer, siblingid integer);

declare @siblings table (userId int, siblingID int);

-- Initialize the @siblings table    
insert into @siblings(userId, siblingID)
    select 1 as userID, 2 as siblingID union all
    select 1 as userID, 3 as siblingID union all
    select 6 as userID, 5 as siblingID union all
    select 5 as userID, 3 as siblingID union all
    select 3 as userID, 1 as siblingID union all
    select 4 as userID, 6 as siblingID;

-- Initialize all siblings.  Note that both pairs are going in here    
insert into @allsiblings(userid, siblingid)
    select userId, siblingid from @siblings union
    select siblingID, userid from @siblings

-- select * from @allsiblings

while (1=1)
begin
    -- Add in new siblings, that don't exist by doing a self-join to traverse the links
    insert into @allsiblings
        select distinct sa.userid, sa2.siblingid
        from @allsiblings sa join
             @allsiblings sa2
             on sa.siblingid = sa2.userid
        where not exists (select * from @allsiblings sa3 where sa3.userid = sa.userid and sa3.siblingid = sa2.siblingid)

    -- If nothing was added, we are done        
    if (@@ROWCOUNT = 0) break;

    select * from @allsiblings;
end;    

【讨论】:

    【解决方案3】:

    您可以使用循环和临时表来模拟递归。首先在临时表中插入起始节点。然后当临时表中有行时,获取第一行,将其从临时表中删除,并在其中插入他所有的兄弟姐妹...

    【讨论】:

      【解决方案4】:

      http://sqlfiddle.com/#!4/0ef0c/5 是一个示例,其中有人必须获取某些条目的所有亲属。

      对应的栈溢出问题在这里: Hierarchical Query Needs to Pull Children, Parents and Siblings

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-12
        • 1970-01-01
        • 2016-01-12
        • 1970-01-01
        • 2013-08-01
        相关资源
        最近更新 更多