2013-05-14 91 views
2

在Mysql中有很多关于递归SELECT查询的问题,但大多数答案是“Mysql中的递归SELECT查询没有解决方案”。@ Symbol - Mysql中递归SELECT查询的解决方案?

其实是有一定的解决方案&我想清楚地知道它,所以这个问题是对前一个问题,可以在(how-to-do-the-recursive-select-query-in-mysql

可以找到以下假设你有这个表:

col1 - col2 - col3 
1 - a - 5 
5 - d - 3 
3 - k - 7 
6 - o - 2 
2 - 0 - 8 

&你想找出所有连接在COL1到值“1”的联系,也就是说你想打印出:

1 - a - 5 
5 - d - 3 
3 - k - 7 

然后你可以使用这个简单的查询:

select col1, col2, @pv:=col3 as 'col3' from table1 
join 
(select @pv:=1)tmp 
where [email protected] 

好,好,但是,如果你的表中有2条记录COL1包含 “1” & 2记录COL1含有 “3”,例如:

col1 - col2 - col3 
1 - a - 5 
1 - m - 9 
5 - d - 3 
3 - k - 7 
6 - o - 2 
3 - v - 10 
2 - 0 - 8 

然后,当用户在col1中搜索“1”,它应该显示所有环节连接2“1”,即它应该显示这个预期结果:

col1 - col2 - col3 
1 - a - 5 
1 - m - 9 
5 - d - 3 
3 - k - 7 
3 - v - 10 

所以,我的问题是我们如何修改上面的查询,以便它会显示所有链接,如上面的预期结果?

编辑: @戈登, 但如果我们忽略select distinct col1, col2 from那么这个查询意味着什么,你可以在这方面的工作(因为childID的得到了提高,所以我们可以订购表1):

select col1, col2, 
     @pv:=(case when find_in_set(col3, @pv) then @pv else concat(@pv, ',', col3) 
       end) as 'col3' 
    from (select * from table1 order by col1) tb1 join 
     (select @pv:='1') tmp 
     on find_in_set(col1, @pv) > 0 

在这种情况下,我们不担心顺序,例如,如果是这样的数据:

col1 - col2 - col3 
4 - a - 5 
1 - d - 2 
1 - k - 4 
2 - o - 3 
6 - k - 8 
8 - o - 9 

输出将是:

col1 - col2 - col3 
1 - d - 1,2 
1 - k - 1,2,4 
2 - o - 1,2,4,3 

所以我们得到这个结果1,2,4,3对不对? &我们只需选择所有记录,如果col1在1,2,4,3。然后我们可以得到最终的预期结果。

如果是这样的话,你能想到任何特殊情况,排除我刚刚提到的解决方案吗?

+0

这似乎是一个问题,它依赖于以正确的顺序返回的记录。例如,如果我将测试数据插入到表中,但将其插入到相反的顺序中,则SQL仅返回第一行(其中col1 = 1)。其他记录在找到父母之前已被处理并丢弃。为了解决这个问题,您需要添加一个订单子句,并且没有明显的方法来为您的数据做到这一点。下面的@GordonLinoff解决方案遭受类似的痛苦。 – Kickstart 2013-05-14 12:35:25

+0

是的,那是第二个 – Tum 2013-05-14 13:39:42

+0

也许,那些说递归SELECT没有解决方案的人有第二个问题。 (意思是说,毕竟没有实际的,可靠的解决方案。) – 2013-05-16 18:21:42

回答

2

我一直在想,如果像这样的工作:

select distinct col1, col2 
from (select col1, col2, 
      @pv:=(case when find_in_set(col3, @pv) then @pv else concat(@pv, ',', col3) 
        end) as 'col3' 
     from table1 join 
      (select @pv:='1') tmp 
      on find_in_set(col1, @pv) > 0 
    ) t 

像这样的东西应该为小数据集工作。然而,将所有ID放入字符串的想法仅限于字符串的容量。

+0

Thax u Gordon,它几乎就在那里,就像Kicktart说的,如果按照相反的顺序,你的查询不起作用。你想知道如何解决订单问题吗? – Tum 2013-05-14 14:01:46

+0

字符串可能不是一个isue,因为只有20-30个链接? 你是否这么认为? – Tum 2013-05-14 14:20:56

0

有更多的玩法。由于项目的顺序,无法使用用户变量使其工作。

但是,如果你有水平的一个合理的最大数,那么你可以做这样的事情: -

SELECT CONCAT_WS('-', a.allCols, b.allCols, c.allCols, d.allCols, e.allCols, f.allCols, g.allCols, h.allCols, i.allCols, j.allCols, k.allCols, l.allCols, m.allCols) 
FROM (SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) a 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) b ON a.col3 = b.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) c ON b.col3 = c.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) d ON c.col3 = d.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) e ON d.col3 = e.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) f ON e.col3 = f.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) g ON f.col3 = g.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) h ON g.col3 = h.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) i ON h.col3 = i.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) j ON i.col3 = j.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) k ON j.col3 = k.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) l ON k.col3 = l.col1 
LEFT OUTER JOIN(SELECT col1, col3, CONCAT(col1, col2, col3) AS allCols FROM table1) m ON l.col3 = m.col1 
WHERE a.col1 = 1 

这与多达13个级别(OK,在您的测试数据用一对夫妇只)应对,并为每列提供一个以逗号分隔的位,每行用短划线( - )连接。

+0

但链接的数量未知,即它可能只有3个链接或5个链接或20个链接 – Tum 2013-05-15 00:48:17

+0

无关紧要,只要您至少有多少个连接即可。你说只有20〜30个链接,所以应该很容易覆盖这个。 – Kickstart 2013-05-15 08:06:58

+0

我坚持戈登的解决方案。不管怎样,谢谢你。 – Tum 2013-05-15 11:19:10

0

在我有限的层次,水平的深,我用了以下内容:

父母:

select * from mytable 
join (
    select A.id Aid,B.id Bid, C.id Cid, D.id Did, E.id Eid, F.id Fid,G.id Gid, H.id Hid from mytable A 
    left join mytable B on B.id=A.parent 
    left join mytable C on C.id=B.parent 
    left join mytable D on D.id=C.parent 
    left join mytable E on E.id=D.parent 
    left join mytable F on F.id=E.parent 
    left join mytable G on G.id=F.parent 
    left join mytable H on H.id=G.parent 
    where A.id=9 
) X 
where id in (Aid,Bid,Cid,Did,Eid,Fid,Gid,Hid); 

孩子:

select * from mytable where id in (
select distinct id from mytable 
join (
    select A.id Aid,B.id Bid, C.id Cid, D.id Did, E.id Eid, F.id Fid,G.id Gid, H.id Hid FROM mytable A 
    left join mytable B on B.parent=A.id 
    left join mytable C on C.parent=B.id 
    left join mytable D on D.parent=C.id 
    left join mytable E on E.parent=D.id 
    left join mytable F on F.parent=E.id 
    left join mytable G on G.parent=F.id 
    left join mytable H on H.parent=G.id 
    Where A.id=1 
) X 
where id in (Aid,Bid,Cid,Did,Eid,Fid,Gid,Hid) 

);

0

存储过程是最好的方法。因为戈登的解决方案只有在数据遵循相同的顺序时才有效。

如果我们有这样

col1 - col2 - col3 
3 - k - 7 
5 - d - 3 
1 - a - 5 
6 - o - 2 
2 - 0 - 8 

它不会工作表结构。

下面是一个示例过程代码来实现相同。

delimiter // 
CREATE PROCEDURE chainReaction 
(
    in inputNo int 
) 
BEGIN 
    declare final_id int default NULL; 
    SELECT col3 into final_id from table1 
    where col1 = inputNo; 
    if(final_id is not null) then 
     insert into results(select col1, col2, col3 from table1 where col1 = inputNo); 
     CALL chainReaction(final_id); 
    end if; 
END// 
delimiter ; 

call chainReaction(1); 
select * from results; 
drop table if exists results;