2017-10-10 43 views
1

在尝试为这个问题找到一个合适的解决方案并且几乎将所有的头发都拉出来之后,我决定前来寻求帮助。按照CTE的年龄段划分父母和子女的年龄

问题:
我有4列,看起来像这样的表:

id | family_id | parent_id | age | 
------------------------------------- 
1 | 1   | 0  | 45 | 
2 | 1   | 7  | 23 | 
3 | 1   | 0  | 59 | 
4 | 1   | 5  | 12 | 
5 | 1   | 1  | 27 | 
6 | 1   | 7  | 18 | 
7 | 1   | 1  | 30 | 
8 | 1   | 1  | 32 | 
9 | 1   | 6  | 9  | 

使用CTE我找出谁是孩子是父母的,并通过路径排序他们,与父母相关联。像这样:

WITH RECURSIVE cte (id, path, family_id, parent_id, age) AS (
    SELECT id, array[id] AS path, family_id, parent_id, age 
     FROM test 
     WHERE parent_id=0 
     AND family_id=1 

     UNION ALL 

     SELECT test.id, 
       cte.path || test.id, 
       test.family_id, 
       test.parent_id, 
       test.age 
     FROM test 
     JOIN cte ON test.parent_id = cte.id 
) 
SELECT id, path, family_id, parent_id, age 
FROM cte 
ORDER BY path; 

结果,一个很好的表,由父母及其子女排序。

id | path  |family_id | parent_id | age | 
------------------------------------------------- 
1 | 1  | 1  | 0  | 45 | 
2 | 1,2  | 1  | 1  | 30 | 
3 | 1,3  | 1  | 1  | 27 | 
4 | 1,4  | 1  | 1  | 32 | 
5 | 5  | 1  | 0  | 59 | 
6 | 5,6  | 1  | 5  | 12 | 
7 | 5,6,7 | 1  | 6  | 9  | 
8 | 5,6,7,8 | 1  | 7  | 18 | 
9 | 5,6,7,9 | 1  | 7  | 23 | 



现在到了真正的挑战(太多头发拉出...)
应该怎样处理我的查询看起来像这样它 种种每一个家长(和链接子女)按年龄(最高年龄第一)?

最终的结果应该是这样的:

id | path  |family_id | parent_id | age | 
------------------------------------------------- 
1 | 5  | 1  | 0  | 59 | 
2 | 5,6  | 1  | 5  | 12 | 
3 | 5,6,7 | 1  | 6  | 9  | 
4 | 5,6,7,8 | 1  | 7  | 23 | 
5 | 5,6,7,9 | 1  | 7  | 18 | 
6 | 1  | 1  | 0  | 45 | 
7 | 1,2  | 1  | 1  | 32 | 
8 | 1,3  | 1  | 1  | 30 | 
9 | 1,4  | 1  | 1  | 27 | 

该解决方案不工作:

ORDER BY path, age; 


的演示是在SQL小提琴提供: SQLFIDDLE DEMO

回答

1

这个人是不是优雅,但似乎工作:

WITH RECURSIVE cte (id, path, family_id, parent_id, age, sort_col) AS (
     SELECT id, array[id] AS path, family_id, parent_id, age, array[age, -id] 
     FROM test 
     WHERE parent_id=0 
     AND family_id=1 

     UNION ALL 

     SELECT test.id, 
       cte.path || test.id, 
       test.family_id, 
       test.parent_id, 
       test.age, 
       cte.sort_col || test.age || -test.id 
     FROM test 
     JOIN cte ON test.parent_id = cte.id 
) 
SELECT id, path, family_id, parent_id, age, array_append(sort_col, 999) 
FROM cte 
ORDER BY array_append(sort_col, 999) desc, path; 

http://sqlfiddle.com/#!17/328ac/109

创建一个列(数组)就像你与path做的,而是用age代替id。对于路径5,6,7,此列将为59,12,9。对于关系,您还应该附加id(或-id - 取决于您是希望低位还是高位优先)。现在列将是59,-5,12,-6,9,-7。最后一步:在主语句中附加999 - 这样父节点总是会在子节点之前出现(假设没有人比这更旧( - :))。

结果是:

id | path | family_id | parent_id | age | array_append 
---|---------|-----------|-----------|-----|--------------------------- 
5 | 5  |   1 |   0 | 59 | 59,-5,999 
6 | 5,6  |   1 |   5 | 12 | 59,-5,12,-6,999 
7 | 5,6,7 |   1 |   6 | 9 | 59,-5,12,-6,9,-7,999 
9 | 5,6,7,9 |   1 |   7 | 23 | 59,-5,12,-6,9,-7,23,-9,999 
8 | 5,6,7,8 |   1 |   7 | 18 | 59,-5,12,-6,9,-7,18,-8,999 
1 | 1  |   1 |   0 | 45 | 45,-1,999 
4 | 1,4  |   1 |   1 | 32 | 45,-1,32,-4,999 
2 | 1,2  |   1 |   1 | 30 | 45,-1,30,-2,999 
3 | 1,3  |   1 |   1 | 27 | 45,-1,27,-3,999 

请注意,我只是为了示范原因选择array_append(sort_col, 999)。您可以从SELECT子句中删除它。

+0

此解决方案解决了我的问题。感谢您对代码的补充说明 –

0
WITH RECURSIVE cte (id, path, family_id, parent_id, age, parent_path, root_age) AS (
    SELECT id, array[id] AS path, family_id, parent_id, age, 
    NULL::integer[] as parent_path, age as root_age 
    FROM test 
    WHERE parent_id=0 
    AND family_id=1 

    UNION ALL 

    SELECT test.id, 
      cte.path || test.id, 
      test.family_id, 
      test.parent_id, 
      test.age, 
      cte.path AS parent_path, 
      cte.root_age AS root_age 
    FROM test 
    JOIN cte ON test.parent_id = cte.id 
) 
SELECT id, path, family_id, parent_id, age, parent_path, root_age 
FROM cte 
ORDER BY root_age DESC, coalesce(parent_path, path), parent_path IS NULL DESC, age DESC; 

Sor我的原始答案。

对于解决方案需要一个没有自我id的路径。这是“parent_path”字段。 有了这个列,排序很简单。 异常是没有parent_path的行,即parent_path为null的根。为了排序,需要coalesce()和parent_path为空desc。

要订购根元素,您需要一个“root_age”字段。这应该启动ORDER BY子句。

+0

您可能想要考虑编辑您的答案,以包含您的代码的说明,以让其他用户更好地理解您的解决方案。 –

+0

变得非常接近,但并不完美。排序应该是相反的(从高到低,而不是从低到高)。你可以在你的例子中解决这个问题吗? –

+0

Thx用于快速更新。根(没有parent_path的行)仍然排序从低到高(也应该从高到低) –