将 Oracle 中的 CONNECT_BY_ISLEAF 替换为 Postgres
Replace CONNECT_BY_ISLEAF in Oracle to Postgres
如何将此查询转换为其等效的 postgresql 分层查询?
如何替换postgresql中的CONNECT_BY_ISLEAF函数?
SELECT emp_id,mgr_id,name,SYS_CONNECT_BY_PATH (name,'/') PATH ,CONNECT_BY_ISLEAF ISLEAF
FROM employee
START WITH (emp_id = 345)
CONNECT BY NOCYCLE (PRIOR emp_id = mgr_id)
这在 Oracle 中使用递归 Sub-Query 分解子句(a.k.a。通用 Table 表达式)是等效的。它应该映射(可能在语法上有一些变化)到 PostgreSQL:
WITH cte ( emp_id, mgr_id, name, path, leaf ) AS (
SELECT emp_id,
mgr_id,
name,
'/' || name,
CASE WHEN EXISTS( SELECT 1 FROM employee m WHERE m.mgr_id = e.emp_id )
THEN 0 ELSE 1 END
FROM employee e
WHERE emp_id = 345
UNION ALL
SELECT e.emp_id,
e.mgr_id,
e.name,
c.path || '/' || e.name,
CASE WHEN EXISTS( SELECT 1 FROM employee m WHERE m.mgr_id = e.emp_id )
THEN 0 ELSE 1 END
FROM employee e
INNER JOIN cte c
ON( e.mgr_id = c.emp_id )
)
SELECT * FROM cte;
(注意:这不考虑分层查询的 NOCYCLE
子句 - 如果这是必要的,那么您将需要建立一种机制来消除这些连接。)
递归查询是使用 Postgres 中的递归 common table expression 完成的。
您可以模拟 Oracle 的 level
,只需为每次迭代递增一个值,然后在外部查询中比较该值。
可以使用 sub-query 检查叶子 - 类似于 MT0 所做的
nocycle
可以通过记住所有已处理的行并向递归部分添加 where 条件来完成,如果员工已被处理则停止。
通过携带初始emp_id通过各级,还可以模拟Oracle的connect_by_root
with recursive cte (emp_id, mgr_id, name, path, level, visited, root_id) AS
(
select emp_id,
mgr_id,
name,
'/' || name,
1 as level,
array[emp_id] as visited,
emp_id as root_id
from employee e
where emp_id = 345
union all
select c.emp_id,
c.mgr_id,
c.name,
concat_ws('/', p.path, c.name),
p.level + 1,
p.visited || c.emp_id,
p.root_id
from employee c
join cte p on p.emp_id = c.mgr_id
where c.emp_id <> all(p.visited)
)
SELECT e.*,
not exists (select * from cte p where p.mgr_id = e.emp_id) as is_leaf
FROM cte e;
如何将此查询转换为其等效的 postgresql 分层查询? 如何替换postgresql中的CONNECT_BY_ISLEAF函数?
SELECT emp_id,mgr_id,name,SYS_CONNECT_BY_PATH (name,'/') PATH ,CONNECT_BY_ISLEAF ISLEAF
FROM employee
START WITH (emp_id = 345)
CONNECT BY NOCYCLE (PRIOR emp_id = mgr_id)
这在 Oracle 中使用递归 Sub-Query 分解子句(a.k.a。通用 Table 表达式)是等效的。它应该映射(可能在语法上有一些变化)到 PostgreSQL:
WITH cte ( emp_id, mgr_id, name, path, leaf ) AS (
SELECT emp_id,
mgr_id,
name,
'/' || name,
CASE WHEN EXISTS( SELECT 1 FROM employee m WHERE m.mgr_id = e.emp_id )
THEN 0 ELSE 1 END
FROM employee e
WHERE emp_id = 345
UNION ALL
SELECT e.emp_id,
e.mgr_id,
e.name,
c.path || '/' || e.name,
CASE WHEN EXISTS( SELECT 1 FROM employee m WHERE m.mgr_id = e.emp_id )
THEN 0 ELSE 1 END
FROM employee e
INNER JOIN cte c
ON( e.mgr_id = c.emp_id )
)
SELECT * FROM cte;
(注意:这不考虑分层查询的 NOCYCLE
子句 - 如果这是必要的,那么您将需要建立一种机制来消除这些连接。)
递归查询是使用 Postgres 中的递归 common table expression 完成的。
您可以模拟 Oracle 的 level
,只需为每次迭代递增一个值,然后在外部查询中比较该值。
可以使用 sub-query 检查叶子 - 类似于 MT0 所做的
nocycle
可以通过记住所有已处理的行并向递归部分添加 where 条件来完成,如果员工已被处理则停止。
通过携带初始emp_id通过各级,还可以模拟Oracle的connect_by_root
with recursive cte (emp_id, mgr_id, name, path, level, visited, root_id) AS
(
select emp_id,
mgr_id,
name,
'/' || name,
1 as level,
array[emp_id] as visited,
emp_id as root_id
from employee e
where emp_id = 345
union all
select c.emp_id,
c.mgr_id,
c.name,
concat_ws('/', p.path, c.name),
p.level + 1,
p.visited || c.emp_id,
p.root_id
from employee c
join cte p on p.emp_id = c.mgr_id
where c.emp_id <> all(p.visited)
)
SELECT e.*,
not exists (select * from cte p where p.mgr_id = e.emp_id) as is_leaf
FROM cte e;