2013-05-14 84 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;