2012-04-02 64 views
1

我有一個表中的用戶,其中有一個字段'id',另一個字段是'parent id'。此外,我還預期用戶表中的目標字段。數據庫表中的多級用戶

我有用戶列表,直到第8級的層次結構。 A是B的父母,B是C的父母,等等。

e.g

A level 0 
| 
B level 1 
| 
c level 2 

現在,當我在尋找用戶A.我想使用SQL查詢中的所有子用戶的預期目標「。 即當我使用ID = ID的A,那麼我可以看到A,B,C等的預期目標。

如果A,B和C的expected_targets分別爲1000,500,200,則輸出應該如下所示:

id  parent_id  expected_target 

A_id      1000 
B_id  A_id   500 
C_id  B_id   200 
+0

此數據庫結構是否「鎖定」?我想不出任何使用標準SQL進行這種操作的高性能方式(7級自連接並不是我建議的) – 2012-04-02 09:29:32

+0

它看起來像[ltree](http://www.postgresql。 org/docs/current/static/ltree.html)模塊是爲了解決 – 2012-04-02 10:34:49

+0

@JoachimIsaksson 7個自連接有什麼問題..它是完全合理的,如果層數保證;)但我不明白什麼是*預期目標* - 結果應該是行還是列? – Aprillion 2012-04-02 10:55:15

回答

1

這將做的工作 - http://sqlfiddle.com/#!2/0de1f/7

select u1.id, u1.parent_id, u1.expected_target 
from users u1 
left join users u2 on u1.parent_id = u2.id 
left join users u3 on u2.parent_id = u3.id 
left join users u4 on u3.parent_id = u4.id 
left join users u5 on u4.parent_id = u5.id 
left join users u6 on u5.parent_id = u6.id 
left join users u7 on u6.parent_id = u7.id 
left join users u8 on u7.parent_id = u8.id 
where :A_id in (u1.id, u2.id, u3.id, u4.id, u5.id, 
       u6.id, u7.id, u8.id, u8.parent_id) 
1
SET search_path='tmp'; 

DROP TABLE targets CASCADE; 
CREATE TABLE targets 
     (id integer not null primary key 
     , parent_id integer references targets(id) 
     , expected_target integer 
     ); 

INSERT INTO targets(id,parent_id,expected_target) VALUES 
(1,NULL, 1000), (2,1, 500), (3,2, 200); 


WITH RECURSIVE zzz AS (
     SELECT t0.id, t0.parent_id 
     , 0::integer AS level 
     , t0.expected_target 
     FROM targets t0 
     WHERE t0.parent_id IS NULL 
     UNION 
     SELECT t1.id, t1.parent_id 
     , 1+zzz.level AS level 
     , t1.expected_target 
     FROM targets t1 
     JOIN zzz ON zzz.id = t1.parent_id 
     ) 
SELECT * FROM zzz 
     ; 

OUTPUT:

SET 
DROP TABLE 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "targets_pkey" for table "targets" 
CREATE TABLE 
INSERT 0 3 
id | parent_id | level | expected_target 
----+-----------+-------+----------------- 
    1 |   |  0 |   1000 
    2 |   1 |  1 |    500 
    3 |   2 |  2 |    200 
(3 rows) 

UPDATE:如果你不想整棵樹,真正的樹,不過是樹而只是它的一個子樹的一部分,當然你也可以改變條件位:

WITH RECURSIVE zzz AS (
     SELECT t0.id, t0.parent_id 
     , 0::integer AS level 
     , t0.expected_target 
     FROM targets t0 
     -- WHERE t0.parent_id IS NULL 
     WHERE t0.id = 2 
     UNION 
     SELECT t1.id, t1.parent_id 
     , 1+zzz.level AS level 
     , t1.expected_target 
     FROM targets t1 
     JOIN zzz ON zzz.id = t1.parent_id 
     ) 
SELECT * FROM zzz 
     ; 
+0

+1我不知道那裏需要是RECURSIVE關鍵字;) – Aprillion 2012-04-02 11:52:01

+0

這個查詢是好的,但如果我想看到來自id 2的結果,那我該如何編寫這個查詢呢?我試過WHERE t0.id = 2而不是WHERE t0.parent_id IS NULL,但是查詢只是在沒有任何輸出的情況下運行 – 2012-04-03 06:10:43

+0

「id 2的結果」是什麼意思?只有id = 2?(看起來很平常)id = 2;包括孩子a孫子和完整的後代? – wildplasser 2012-04-03 08:52:33

0

由於這是標記的PostgreSQL:

with recursive users_tree as (
    select id, 
     parent_id, 
     expected_target, 
     1 as level 
    from users 
    where id = 'A_id' 

    union all 

    select c.id, 
     c.parent_id, 
     c.expected_target, 
     p.level + 1 
    from users c 
    join users_tree p on c.parent_id = p.id 
) 
select * 
from users_tree 

MySQL是不夠先進,以支持這一點。你需要爲每個關卡做一個自我連接。

+0

該查詢無法在運行時完成。 – 2012-04-03 06:11:42

+0

@SuryawanshiManoj:那麼顯然你在你的數據中有一些循環(一個id指向一個父指向id本身 - 也許在幾個級別上) – 2012-04-03 06:51:05