2015-09-22 96 views
2

查詢層次結構的最佳方法假設我有類別的層次結構,如下:Postgres的:按名稱

id |  name | parent_id 
---+------------+----------- 
1 | Computers | 
---+------------+----------- 
2 | Laptops | 1 
---+------------+----------- 
3 | Desktops | 1 
---+------------+----------- 
4 | Big  | 2 
---+------------+----------- 
5 | Small  | 2 
---+------------+----------- 
4 | Big  | 3 
---+------------+----------- 
5 | Small  | 3 

現在,假如有人給我輸入['Computers', 'Laptops', 'Small']。 Postgres查詢層次結構併到達正確的最終類別(例如,ID 5)的最佳方式是什麼?

我知道你可以使用遞歸CTE來遍歷樹,但是什麼是將輸入數組參數化到查詢中的最佳方式?

下或多或少的作品,但感覺真的分面值的,因爲你要分手了,參數數組:

WITH RECURSIVE path(n, id, name, parent_id) AS (
    SELECT 
    1, c.id, c.name, c.parent_id 
    FROM 
    categories c 
    WHERE c.name = 'Computers' AND parent_id IS NULL 
    UNION ALL 
    SELECT n+1, c.id, c.name, c.parent_id 
    FROM categories c, 
    (SELECT * FROM unnest(ARRAY['Laptops', 'Small']) WITH ORDINALITY np(name, m)) np, 
    path p 
    WHERE c.parent_id = p.id AND np.m = n AND np.name = c.name 
) 
SELECT * FROM path; 
+0

這就是爲什麼我錯過這麼多'level'和'從Oracle連接by'到PostgreSQL的 –

回答

1

的CTE應該是這樣的:

WITH RECURSIVE search AS (
    SELECT ARRAY['Computers', 'Laptops', 'Small'] AS terms 
), path (n, id, name, parent_id) AS (
    SELECT 1, id, name, parent_id 
    FROM categories, search 
    WHERE name = terms[1] 
    UNION 
    SELECT p.n+1, c.id, c.name, c.parent_id 
    FROM categories c, path p, search s 
    WHERE c.parent_id = p.id 
    AND c.name = (s.terms)[p.n+1] 
) 
SELECT * FROM path; 

整潔事情是,你只需指定一次數組,然後CTE的其他項就可以遍歷數組,無論路徑多長。不需要解開。請注意,這也適用於部分樹:['桌面','大']將很好地產生正確的路徑(顯然不包括'計算機')。

SQLFiddle here

+0

謝謝!增加了'AND parent_id IS NULL'來確保我們總是從一個根類別開始。 – Jake