表中的sql层次结构

时间:2016-08-07 19:58:06

标签: sql postgresql

我使用postgres 9.5。 我需要存储这样的(树状)数据:

  • 1a级
    • 2a级
      • level 3a
      • level 3b
    • 等级2b
  • 等级1b

    • 2a级
    • 等级2b
  • 1c级

  • 等级1d

这是我的sql表:

CREATE TABLE matieres_test ( id serial NOT NULL CONSTRAINT matieres_test_id_pk PRIMARY KEY, name varchar NOT NULL, parent INT DEFAULT NULL, CONSTRAINT matieres_test_parent_fk FOREIGN KEY (parent) REFERENCES matieres_test(id) );

并插入(如果易于阅读,则列表)

insert into matieres_test(id,name,parent) values (1,'level 1a',null);
    insert into matieres_test(id,name,parent) values (5,'level 2a ',1);
        insert into matieres_test(id,name,parent) values (9,'level 3a',5);
        insert into matieres_test(id,name,parent) values (10,'level 3b',5); 
    insert into matieres_test(id,name,parent) values (6,'level 2b', 1);

insert into matieres_test(id,name,parent) values (2,'level 1b',null);
    insert into matieres_test(id,name,parent) values (7,'level 2a',2);
    insert into matieres_test(id,name,parent) values (8,'level 2b',2); 

insert into matieres_test(id,name,parent) values (3,'level 1c',null);
insert into matieres_test(id,name,parent) values (4,'level 1d',null);

现在我想获取数据,我的查询:

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM matieres_test AS t1
LEFT JOIN matieres_test AS t2 ON t2.parent = t1.id
LEFT JOIN matieres_test AS t3 ON t3.parent = t2.id
LEFT JOIN matieres_test AS t4 ON t4.parent = t3.id

结果:

    |   lev1    |  lev2     |   lev3
----|-----------|-----------|----------    
 1  |  level 1a | level 2a  | level 3b  
 2  |  level 1a | level 2a  | level 3a  
 3  |  level 2a | level 3b  |
 4  |  level 1b | level 2b  |
 5  |  level 1a | level 2b  |
 6  |  level 1b | level 2a  |
 7  |  level 2a | level 3a  |
 8  |  level 3b |
 9  |  level 2b |
 10 |  level 2b |
 11 |  level 2a |
 12 |  level 1d |
 13 |  level 1c |
 14 |  level 3a |

问题是它返回错误的行(第3,7,8,9,10,11,14行) 因为我在“lev1”栏等中得到“等级2a”......

我需要这样的东西:

    |   lev1    |  lev2     |   lev3
----|-----------|-----------|---------- 
    |  level 1a | level 2a  | level 3a  
    |  level 1a | level 2a  | level 3b  
    |  level 1a | level 2b  |
    |  level 1b | level 2a  |  
    |  level 1b | level 2b  |
    |  level 1d |
    |  level 1c |

请问好吗?

2 个答案:

答案 0 :(得分:2)

看起来您需要做的就是约束查询,以便lev1记录nullparent

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM matieres_test AS t1
LEFT JOIN matieres_test AS t2 ON t2.parent = t1.id
LEFT JOIN matieres_test AS t3 ON t3.parent = t2.id
LEFT JOIN matieres_test AS t4 ON t4.parent = t3.id
WHERE t1.parent IS NULL -- add this condition
-- and an optional ORDER BY clause if you need the result in a specific order...

添加where子句后,结果变为:

lev1       lev2       lev3       lev4
---------- ---------- ---------- ----------
level 1a   level 2a   level 3a   NULL
level 1a   level 2a   level 3b   NULL
level 1a   level 2b   NULL       NULL
level 1b   level 2a   NULL       NULL
level 1b   level 2b   NULL       NULL
level 1c   NULL       NULL       NULL
level 1d   NULL       NULL       NULL

答案 1 :(得分:1)

SELECT DISTINCT
  t1.name AS lev1,
  t2.name AS lev2,
  t3.name AS lev3,
  t4.name AS lev4
FROM matieres_test AS t1
LEFT JOIN matieres_test AS t2
  ON t2.parent = t1.id
LEFT JOIN matieres_test AS t3
  ON t3.parent = t2.id
LEFT JOIN matieres_test AS t4
  ON t4.parent = t3.id
WHERE t1.parent IS NULL
ORDER BY lev1, lev2, lev3, lev4;

您必须为t1.parent添加IS NULL项检查。使用给定的ORDER BY子句,您可以正确地对结果进行排序。