将Oracle中的CONNECT_BY_ISLEAF替换为Postgres

时间:2017-02-03 10:52:38

标签: sql postgresql hierarchical-data recursive-query

如何将此查询转换为其等效的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)

2 个答案:

答案 0 :(得分:2)

这在Oracle中使用递归子查询分解子句(a.k.a. Common Table Expression)等效。它应该映射(可能在语法上有一些变化)到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子句 - 如果这是必要的,那么您将需要构建一个机制来消除这些连接。) < / p>

答案 1 :(得分:2)

使用Postgres中的递归common table expression进行递归查询。

您可以通过简单地为每次迭代增加一个值然后在外部查询中比较它来模拟Oracle的level

可以使用子查询检查叶子 - 类似于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;

在线示例:http://rextester.com/TSMVV17478