2013-07-15 36 views
2

我無法圍繞一個小的(希望的)MySQL問題包裹我的頭。我有一個叫做鏈接的表格。它包含一個customer_id字段和一個linked_id字段,並且基本上將customer_id引導到彼此的客戶賬戶。新創建的帳戶可以自行生成帳戶,我希望看到由登錄用戶創建的所有帳戶+由子帳戶創建的所有帳戶。MySQL從同一個表中獲得鏈接的結果

表看起來是這樣的:

+----+-------------+-----------+ 
| id | customer_id | linked_id | 
+----+-------------+-----------+ 
| 1 |   1 |   5 | 
| 2 |   1 |   2 | 
| 3 |   1 |  11 | 
| 4 |   1 |  13 | 
| 5 |   13 |  14 | 
| 6 |   3 |   4 | 
| 7 |   7 |   8 | 
+----+-------------+-----------+ 

所以,如果我的身份登錄與CUSTOMER_ID 1用戶然後我想與linked_id 5,2,11,13得到用戶列表(因爲它們是直接連接)和linked_id 14(因爲該用戶是由直接連接到1的用戶創建的)。

該查詢需要是子查詢才能獲取所有用戶詳細信息。我目前有:

SELECT username, firstname, lastname, email, active, level FROM customers WHERE id 
IN (SELECT linked_id FROM links WHERE customer_id=1) or id=1; 

這顯然只直接返回直接連接和id = 1的用戶。

+0

你只希望看到「孩子」和「孫子女」嗎?還是所有的後代,無論深度如何? – eggyal

+0

無論深度如何,我都希望所有的後代,所以如果用戶使用ID 14創建新的孩子,這些也應該列在'主'ID下,然後1 – lleto

+5

然後你需要MySQL來遍歷你現有的數據模型,這是遞歸地稱爲「*鄰接列表*」;但是,與其他一些RDBMS不同,MySQL不支持遞歸函數。如果可能的話,你可能會考慮重塑使用不同的數據結構,如「*嵌套集*」或「*傳遞閉包*」。 – eggyal

回答

1

感謝eggyal讓我走上正軌。看到相對的復​​雜性,我不再感到羞愧,因爲我無法在一開始就破解它。

我最終做了一些研究,發現了一些很好的設置,以便在mysql中使用閉包表。我最終創建了一個存儲過程來填充我的閉包表,當然還有新的表cust_closure。我將鏈接表重命名爲cust_links。

cust_links:

+-------------+---------+------+-----+---------+----------------+ 
| Field  | Type | Null | Key | Default | Extra   | 
+-------------+---------+------+-----+---------+----------------+ 
| id   | int(11) | NO | PRI | NULL | auto_increment | 
| customer_id | int(11) | YES |  | NULL |    | 
| linked_id | int(11) | YES |  | NULL |    | 
+-------------+---------+------+-----+---------+----------------+ 

cust_closure:

+-------------+---------+------+-----+---------+-------+ 
| Field  | Type | Null | Key | Default | Extra | 
+-------------+---------+------+-----+---------+-------+ 
| customer_id | int(11) | YES |  | NULL |  | 
| linked_id | int(11) | YES |  | NULL |  | 
| distance | int(11) | YES |  | NULL |  | 
+-------------+---------+------+-----+---------+-------+ 

,然後添加存儲過程:

CREATE PROCEDURE populate_cust_closure() 
BEGIN 
    DECLARE distance int; 
    TRUNCATE TABLE cust_closure; 
    SET distance = 0; 
    -- seed closure with self-pairs (distance 0) 
    INSERT INTO cust_closure (customer_id, linked_id, distance) 
    SELECT customer_id, customer_id, distance 
     FROM cust_links GROUP BY customer_id; 

    -- for each pair (root, leaf) in the closure, 
    -- add (root, leaf->child) from the base table 
    REPEAT 
    SET distance = distance + 1; 
    INSERT INTO cust_closure (customer_id, linked_id, distance) 
     SELECT cust_closure.customer_id, cust_links.linked_id, distance 
     FROM cust_closure, cust_links 
      WHERE cust_closure.linked_id = cust_links.customer_id 
      AND cust_closure.distance = distance - 1; 
    UNTIL ROW_COUNT()=0 
    END REPEAT; 
END // 

當我再調用的存儲過程就產生d:

mysql> select * from cust_closure; 
+-------------+-----------+----------+ 
| customer_id | linked_id | distance | 
+-------------+-----------+----------+ 
|   1 |   1 |  0 | 
|   3 |   3 |  0 | 
|   7 |   7 |  0 | 
|   13 |  13 |  0 | 
|   1 |   5 |  0 | 
|   1 |   2 |  0 | 
|   1 |  11 |  0 | 
|   1 |  13 |  0 | 
|   13 |  14 |  0 | 
|   1 |  14 |  1 | 
|   3 |   4 |  0 | 
|   7 |   8 |  0 | 
+-------------+-----------+----------+ 

所以現在我原來的查詢就會變成:

SELECT username, firstname, lastname, email, active, level FROM customers WHERE id 
IN (SELECT linked_id FROM cust_closure WHERE customer_id=1); 

再次感謝eggyal,希望這可以幫助別人的未來。

相關問題