2012-04-02 66 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