2014-03-04 140 views
0

我有如下表:獲取頂級父的MySQL

id | parent_id | searchable | value 
-------------------------------------------- 
    1 |  0  |  0  | a 
    2 |  1  |  0  | b 
    3 |  2  |  1  | c 
    4 |  0  |  0  | d 
    5 |  4  |  1  | e 
    6 |  0  |  0  | f 
    7 |  6  |  0  | g 
    8 |  6  |  0  | h 
    9 |  0  |  1  | i 

我需要提取所有的頂級記錄(所以那些在parent_id = 0)。 但只有記錄中,其中父母或他的一個孩子是搜索(searchable = 1

在這種情況下

因此,輸出應該是:

id | parent_id | searchable | value 
-------------------------------------------- 
    1 |  0  |  0  | a 
    4 |  0  |  0  | d 
    9 |  0  |  1  | i 

因爲這些都是頂級的記錄,它的自我或他的一個孩子(無論這個可搜索的孩子有多'深')都是可搜索的。

我正在使用MySQL。我不確定是否有可能只用一個查詢來編寫它,但我認爲它應該用一段遞歸代碼或函數來完成。

**注意:樹的深度如何「未知」是未知的。

+0

的可能重複[MySQL的 - 遞歸樹結構](http://stackoverflow.com/questions/2378678/mysql-recursing-a-tree-structure) – Mikpa

+0

我讀過文章t帽子被標記爲正確的答案,但我沒有在那裏找到我的答案。對於我正在使用的應用程序,使用左右列的嵌套集模型效率不高 – JasperV

+2

您需要更改數據模型,編寫存儲過程或在應用程序中執行遞歸。您沒有其他選項可以使用MySQL的有限功能。它可以**不能用單個查詢來完成,因爲MySQL缺乏執行遞歸查詢的能力 –

回答

1

你將不得不使用存儲過程來做到這一點。

查找所有包含searchable = 1的行,將它們的id和parent_ids存儲在臨時表中。 然後做自我加入以將父母添加到此臨時表。 重複,直到沒有更多的行可以添加(顯然最好確保樹不循環)。 最後,您只有一個表格,其中只有行中有可搜索的後裔,因此只顯示沒有父項的行(位於頂部)。

假設你的表被稱爲 'MY_TABLE' 這個應該工作:

DELIMITER // 
DROP PROCEDURE IF EXISTS top_level_parents// 
CREATE PROCEDURE top_level_parents() 
BEGIN 
    DECLARE found INT(11) DEFAULT 1; 
    DROP TABLE IF EXISTS parent_tree; 
    CREATE TABLE parent_tree (id int(11) PRIMARY KEY, p_id int(11)) ENGINE=HEAP; 
    INSERT INTO parent_tree 
    SELECT id, parent_id FROM my_table 
    WHERE searchable = 1; 
    SET found = ROW_COUNT(); 
    WHILE found > 0 DO 
    INSERT IGNORE INTO parent_tree 
     SELECT p.id, p.parent_id FROM parent_tree c JOIN my_table p 
     WHERE p.id = c.p_id; 
    SET found = ROW_COUNT(); 
    END WHILE; 
    SELECT id FROM parent_tree WHERE p_id = 0; 
    DROP TABLE parent_tree; 
END;// 
DELIMITER ; 

然後,只需調用它:

CALL top_level_parents(); 

將等於 SELECT id FROM my_table WHERE id_is_top_level_and_has_searchable_descendant

+0

正是我需要的!它運行速度非常快,如果你不總是下降並創建它。 – JasperV