2010-05-28 29 views
3

穿越樹木深度嵌套子查詢我有我的數據庫中的表,我使用混合嵌套集合(MPTT)模型(其中有lftrght值而確定一)和鄰接表模型(存儲存儲樹結構每個節點上的parent_id)。在MySQL的

my_table (id, parent_id, lft, rght, alias) 

這個問題不涉及任何的樹MPTT方面,但我想我會留在的情況下,任何人都有關於如何利用這是一個好主意。

我想將別名路徑轉換爲特定節點。例如:"users.admins.nickf"將找到具有別名「nickf」的節點,該別名是具有別名「admins」的別名,該別名是位於根處的「用戶」的子節點。 (parent_id, alias)上有一個唯一索引。

我開始寫的功能,所以它會在路徑拆分其各部分,然後通過一個查詢數據庫中的一個:

SELECT `id` FROM `my_table` WHERE `parent_id` IS NULL AND `alias` = 'users';-- 1 
SELECT `id` FROM `my_table` WHERE `parent_id` = 1 AND `alias` = 'admins'; -- 8 
SELECT `id` FROM `my_table` WHERE `parent_id` = 8 AND `alias` = 'nickf'; -- 37 

但後來我意識到,我可以使用單個查詢做到這一點,利用嵌套的變量數量:

SELECT `id` FROM `my_table` WHERE `parent_id` = (
    SELECT `id` FROM `my_table` WHERE `parent_id` = (
     SELECT `id` FROM `my_table` 
     WHERE `parent_id` IS NULL AND `alias` = 'users' 
    ) AND `alias` = 'admins' 
) AND `alias` = 'nickf'; 

由於子查詢的數量依賴於在路徑的步數,我該怎麼用具有太多的子查詢遇到問題? (如果還有這樣的事情)

有沒有更好/更聰明的方法來執行這個查詢?

+0

你爲什麼不建立一個測試表,並找出查詢(遞歸)棧有多深? – lexu 2010-05-28 04:11:52

+0

不能夠使用最具區分性的選擇器('nickf')'感覺不正確'。也許如果通過連接查詢來構建它,而不是使用子查詢?這將避免遞歸(不是真的,但看起來像)=>級聯自加入! – lexu 2010-05-28 04:15:00

+0

我寫了'自我加入級聯'的好奇心..看到我的答案。 – lexu 2010-05-28 04:28:25

回答

2

這是行不通的嗎?

select r0.id 
    from my_table as r0 
    join my_table as r1 on(r0.parent_id = r1.id) 
    join my_table as r2 on(r1.parent_id = r2.id) 
where r0.alias='nickf' 
    and r1.alias='admins' 
    and r2.alias='users' 
    and r2.parent_id is null 

在我看來,沒有真正需要嵌套子查詢..

還是我錯了,失去了一些東西?

2

我對這件事感到很奇怪,並且正在尋找一些東西,當你走得更深時(這意味着更多的水平在上面的兩個選項中)。我對「我的版本」的問題是它必須在將結果縮小到實際搜索的結果之前創建所有可能的路徑......所以我認爲,即使對於非常大的嵌套,lexu的版本也應該優於我的版本,因爲它是一個簡單的連接,但我希望有人可能會看到它並希望進一步擴大。另外,這種做法肯定會從存儲過程和/或其'路徑'部分(不帶HAVING子句)的視圖中受益。也許對那些人來說,這是一個更好的解決方案,但是現在我不知道SQL的性能是否足夠肯定。我可以說,隨着數據(可能的路徑組合數量)變大,我的速度變慢,但是有了一個視圖(因爲結果被緩存了,並用它來縮小),它似乎很快(我找到的最大數據集在370總,在某些時候,我會創造更大的一組測試。)

SELECT node.id, GROUP_CONCAT(parent.alias 
       ORDER BY parent.lft SEPARATOR '.') AS path_name 
FROM my_table AS node, my_table AS parent 
WHERE node.lft BETWEEN parent.lft AND parent.rght 
GROUP BY node.id HAVING path_name = 'users.admins.nickf' 
+0

任何發生這種情況的人,我都用MySQL中的大數據集進行了測試。這是非常緩慢的,並且意見的使用並不是不幸的。 – Zaahid 2013-11-02 00:40:57