Eri*_*low 4 postgresql cte array recursive
我有一个返回 CTE 的查询,如下所示
+-----------+-------------+
| node_id | ancestors |
|-----------+-------------|
| 1 | [] |
| 2 | [] |
| 3 | [1] |
| 4 | [2] |
| 5 | [4, 2] |
+-----------+-------------+
Run Code Online (Sandbox Code Playgroud)
我想要做的是加入表nodes并将该列中的 id 替换ancestors为表中的另一列nodes。这是我到目前为止的查询:
WITH RECURSIVE tree AS (
-- snip --
)
SELECT node.entity_id AS id,
array_remove(array_agg(parent_nodes.entity_id), NULL) AS ancestors
FROM tree
JOIN entity.nodes AS node ON node.id = tree.node_id
LEFT OUTER JOIN entity.nodes AS parent_nodes ON parent_nodes.id = ANY(tree.ancestors)
GROUP BY node.id;
Run Code Online (Sandbox Code Playgroud)
该查询的问题在于它丢失了原始数组的顺序ancestors。有没有办法在函数执行期间保持原始顺序的同时执行连接array_agg?
您的查询的问题是连接条件id = ANY(ancestors)。它不仅不保留原始顺序,还消除了数组中的重复元素。( Anid可以匹配 中的 10 个元素ancestors,但仍然只会选择一次。)不确定查询的逻辑是否允许重复元素,但如果允许,我很确定您想要保留所有实例 - 您想要保留“毕竟是原始订单”。
假设当前的 Postgres 9.4+由于缺乏信息,我建议采用完全不同的方法:
SELECT n.entity_id, p.ancestors
FROM tree t
JOIN nodes n ON n.id = t.node_id
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT p.entity_id
FROM unnest(t.ancestors) WITH ORDINALITY a(id, ord)
JOIN entity.nodes p USING (id)
ORDER BY ord
) AS ancestors
) p ON true;
Run Code Online (Sandbox Code Playgroud)
nodes.id仅当定义为主键且nodes.entity_id唯一时,您的查询才能按预期工作。问题中缺少信息。
通常,这个没有显式的更简单的查询ORDER BY也可以工作,但没有保证(Postgres 9.3+)...
SELECT n.entity_id, p.ancestors
FROM tree t
JOIN nodes n ON n.id = t.node_id
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT p.entity_id
FROM unnest(t.ancestors) id
JOIN entity.nodes p USING (id)
) AS ancestors
) p ON true;
Run Code Online (Sandbox Code Playgroud)
您也可以确保安全。详细解释:
Postgres 9.3 的SQL Fiddle 演示。
您加入entity.nodes两次 - 替换node_id等等ancestors。另一种方法是将两者折叠成一个数组或一组并仅连接一次。可能会更快,但你必须测试。
对于这些替代方案,我们在任何情况下都需要ORDER BY:
在取消嵌套之前添加node_id到数组中...ancestors
SELECT p.arr[1] AS entity_id, p.arr[2:2147483647] AS ancestors
FROM tree t
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT p.entity_id
FROM unnest(t.node_id || t.ancestors) WITH ORDINALITY a(id, ord)
JOIN entity.nodes p USING (id)
ORDER BY ord
) AS arr
) p ON true;
Run Code Online (Sandbox Code Playgroud)
或者添加到我们加入之前node_id的未嵌套元素......ancestors
SELECT p.arr[1] AS entity_id, p.arr[2:2147483647] AS ancestors
FROM tree t
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT p.entity_id
FROM (
SELECT t.node_id AS id, 0 AS ord
UNION ALL
SELECT * FROM unnest(t.ancestors) WITH ORDINALITY
) x
JOIN entity.nodes p USING (id)
ORDER BY ord
) AS arr
) p ON true;
Run Code Online (Sandbox Code Playgroud)
您没有显示我们的 CTE,这可能会进一步优化...