我有一个简单的查询:
SELECT DISTINCT
dep.DEP_ID,
dep.DEP_NAME,
dep.PARENT_DEP_ID,
emp.SITE_LOCATION
from DEPARTMENT dep
INNER JOIN EMPLOYEE emp ON dep.DEP_ID = emp.DEP_ID
ORDER BY dep.DEP_ID;
这将返回有关departments
的信息,其中某些行具有相同的DEP_ID
,DEP_NAME
和PARENT_DEP_NAME
。这是预期的结果,因为某些员工属于同一部门,但拥有不同的SITE_LOCATION
我要添加另一列MASTER_PARENT_ID
和MASTER父项的DEP_ID
。
我称为主父的是被称为PARENT_DEP_ID
但实际上不存在的主父(DEP_ID
列中缺少值)。
因此,所有这些行实际上应具有等于MASTER_PARENT_ID
的{{1}}值。这只是一个示例数据,但实际上许多行将具有不同的DEP_2000
。并非所有的值都相同。
为此,对于每一行,我需要执行一个递归查询以遍历树,直到找到没有任何匹配MASTER_PARENT_ID
的{{1}}值。 / p>
我试图阅读并理解Oracle文档和示例,但找不到适用于我的案例的工具。是否应该使用PARENT_DEP_ID
之类的东西来执行这种递归功能?
SQL通常不是我的首选,甚至不是Oracle。我找不到解决方法。
谢谢
答案 0 :(得分:1)
您可以使用CONNECT_BY_ISLEAF
伪列来查找层次结构树的叶子,然后在开始导航树时使用CONNECT_BY_ROOT( ... )
函数来获取值:
Oracle 11g R2架构设置:
CREATE TABLE DEPARTMENT( DEP_ID, DEP_NAME, PARENT_DEP_ID ) AS
SELECT 'DEP_2000', 'Dep0', NULL FROM DUAL UNION ALL
SELECT 'DEP_2400', 'Dep1', 'DEP_2000' FROM DUAL UNION ALL
SELECT 'DEP_2410', 'Dep2', 'DEP_2400' FROM DUAL UNION ALL
SELECT 'DEP_2420', 'Dep3', 'DEP_2400' FROM DUAL;
查询1 :
SELECT CONNECT_BY_ROOT( DEP_ID ) AS DEP_ID,
CONNECT_BY_ROOT( DEP_NAME ) AS DEP_NAME,
CONNECT_BY_ROOT( PARENT_DEP_ID ) AS PARENT_DEP_ID,
DEP_ID AS MASTER_PARENT_DEP_ID
FROM DEPARTMENT
WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY PRIOR PARENT_DEP_ID = DEP_ID
Results :
| DEP_ID | DEP_NAME | PARENT_DEP_ID | MASTER_PARENT_DEP_ID |
|----------|----------|---------------|----------------------|
| DEP_2000 | Dep0 | (null) | DEP_2000 |
| DEP_2400 | Dep1 | DEP_2000 | DEP_2000 |
| DEP_2410 | Dep2 | DEP_2400 | DEP_2000 |
| DEP_2420 | Dep3 | DEP_2400 | DEP_2000 |
注意:通过遍历每个元素的树直到根,而不是反向,您不需要START WITH
子句,也不需要单独的查询来查找根。
如果没有DEP_2000
行(只需将DEP_ID
更改为PARENT_DEP_ID
),这甚至可以工作:
Oracle 11g R2架构设置:
CREATE TABLE DEPARTMENT( DEP_ID, DEP_NAME, PARENT_DEP_ID ) AS
--SELECT 'DEP_2000', 'Dep0', NULL FROM DUAL UNION ALL
SELECT 'DEP_2400', 'Dep1', 'DEP_2000' FROM DUAL UNION ALL
SELECT 'DEP_2410', 'Dep2', 'DEP_2400' FROM DUAL UNION ALL
SELECT 'DEP_2420', 'Dep3', 'DEP_2400' FROM DUAL;
查询1 :
SELECT CONNECT_BY_ROOT( DEP_ID ) AS DEP_ID,
CONNECT_BY_ROOT( DEP_NAME ) AS DEP_NAME,
CONNECT_BY_ROOT( PARENT_DEP_ID ) AS PARENT_DEP_ID,
PARENT_DEP_ID AS MASTER_PARENT_DEP_ID
FROM DEPARTMENT
WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY PRIOR PARENT_DEP_ID = DEP_ID
Results :
| DEP_ID | DEP_NAME | PARENT_DEP_ID | MASTER_PARENT_DEP_ID |
|----------|----------|---------------|----------------------|
| DEP_2400 | Dep1 | DEP_2000 | DEP_2000 |
| DEP_2410 | Dep2 | DEP_2400 | DEP_2000 |
| DEP_2420 | Dep3 | DEP_2400 | DEP_2000 |
答案 1 :(得分:0)
如果部门表中根本不存在主部门ID-例如,由于没有直接雇员,它就不会出现在结果中-那么您可以使用分层查询来获取根父级对于每个单位:
select dep_id, dep_name, parent_dep_id,
connect_by_root(parent_dep_id) as master_parent_id
from department
connect by parent_dep_id = prior dep_id
start with parent_dep_id in (
select parent_dep_id from department d1
where not exists (
select *
from department d2
where d2.dep_id = d1.parent_dep_id
)
);
DEP_ID DEP_NAME PARENT_D MASTER_P
-------- --------------- -------- --------
DEP_2400 Department 2400 DEP_2000 DEP_2000
DEP_2410 Department 2410 DEP_2400 DEP_2000
DEP_2420 Department 2420 DEP_2400 DEP_2000
,然后将其用作主查询中的内联视图,而不是直接引用该表:
SELECT DISTINCT
dep.DEP_ID,
dep.DEP_NAME,
dep.PARENT_DEP_ID,
emp.SITE_LOCATION,
dep.MASTER_PARENT_ID
from (
select dep_id, dep_name, parent_dep_id,
connect_by_root(parent_dep_id) as master_parent_id
from department
connect by parent_dep_id = prior dep_id
start with parent_dep_id in (
select parent_dep_id from department d1
where not exists (
select *
from department d2
where d2.dep_id = d1.parent_dep_id
)
)
) dep
INNER JOIN EMPLOYEE emp ON dep.DEP_ID = emp.DEP_ID
ORDER BY dep.DEP_ID;
DEP_ID DEP_NAME PARENT_D SITE_LO MASTER_P
-------- --------------- -------- ------- --------
DEP_2400 Department 2400 DEP_2000 SITE_01 DEP_2000
DEP_2400 Department 2400 DEP_2000 SITE_02 DEP_2000
DEP_2410 Department 2410 DEP_2400 SITE_01 DEP_2000
DEP_2410 Department 2410 DEP_2400 SITE_02 DEP_2000
DEP_2420 Department 2420 DEP_2400 SITE_01 DEP_2000
DEP_2420 Department 2420 DEP_2400 SITE_02 DEP_2000
虽然DEP_2000
实际上存在,并且没有父代,这似乎更自然。如果确实如此,则内联视图会更简单:
SELECT DISTINCT
dep.DEP_ID,
dep.DEP_NAME,
dep.PARENT_DEP_ID,
emp.SITE_LOCATION,
dep.MASTER_PARENT_ID
from (
select dep_id, dep_name, parent_dep_id,
connect_by_root(dep_id) as master_parent_id
from department
connect by parent_dep_id = prior dep_id
start with parent_dep_id is null
) dep
INNER JOIN EMPLOYEE emp ON dep.DEP_ID = emp.DEP_ID
ORDER BY dep.DEP_ID;
请注意,除了start with
子句只是在寻找一个空的父级外,connect_by_root()
现在也在查看dep_id
而不是parent_dep_id
(该值为空) )。