Postgres:按名称查询层次结构的最佳方式
Postgres: Best way to query hierarchy structures by name
假设我的类别层次结构如下:
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;
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 的其他项就可以简单地遍历数组,无论路径有多长。不需要取消嵌套。请注意,这也适用于部分树:['Desktop'、'Big'] 将很好地生成正确的路径(显然不包括 'Computer')。
假设我的类别层次结构如下:
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;
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 的其他项就可以简单地遍历数组,无论路径有多长。不需要取消嵌套。请注意,这也适用于部分树:['Desktop'、'Big'] 将很好地生成正确的路径(显然不包括 'Computer')。