2017-10-10 42 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的行)仍然排序從低到高(也應該從高到低) –