检索每个元素的 MASTER 父级
Retrieve MASTER parent for each element
我有一个简单的查询:
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
的 returns 信息,其中一些行具有相同的 DEP_ID
、DEP_NAME
和 PARENT_DEP_NAME
。这是预期的结果,因为有些员工属于同一部门,但具有不同的 SITE_LOCATION
我想要添加另一列 MASTER_PARENT_ID
和 MASTER 父级的 DEP_ID
。
我称之为主父的是被引用为 PARENT_DEP_ID
但实际上并不存在的那个(DEP_ID
列中缺少值)。
所以所有这些行实际上应该有一个 MASTER_PARENT_ID
值等于 DEP_2000
。这只是一个示例数据,但实际上许多行会有不同的 MASTER_PARENT_ID
。并非所有这些都具有相同的价值。
为此,对于每一行,我需要执行递归查询以遍历整个树,直到找到没有任何匹配 DEP_ID
的 PARENT_DEP_ID
值.
我正在尝试阅读和理解 Oracle 文档和示例,但找不到适合我的案例的内容。我应该使用 CONNECT BY PRIOR
之类的东西来执行这样的递归函数吗?
SQL 总的来说不是我的菜,更不用说 Oracle 了。我找不到解决这个问题的方法。
谢谢
如果主部门 ID 在部门 table 中根本不存在——而不是因为没有直接雇员而没有出现在结果中,例如——那么你可以使用层次结构查询以获取每个部门的根父级:
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
然后将其用作主查询中的内联视图,而不是直接引用 table:
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
(这会为空)。
您可以使用 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
| 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
| 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 |
我有一个简单的查询:
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
的 returns 信息,其中一些行具有相同的 DEP_ID
、DEP_NAME
和 PARENT_DEP_NAME
。这是预期的结果,因为有些员工属于同一部门,但具有不同的 SITE_LOCATION
我想要添加另一列 MASTER_PARENT_ID
和 MASTER 父级的 DEP_ID
。
我称之为主父的是被引用为 PARENT_DEP_ID
但实际上并不存在的那个(DEP_ID
列中缺少值)。
所以所有这些行实际上应该有一个 MASTER_PARENT_ID
值等于 DEP_2000
。这只是一个示例数据,但实际上许多行会有不同的 MASTER_PARENT_ID
。并非所有这些都具有相同的价值。
为此,对于每一行,我需要执行递归查询以遍历整个树,直到找到没有任何匹配 DEP_ID
的 PARENT_DEP_ID
值.
我正在尝试阅读和理解 Oracle 文档和示例,但找不到适合我的案例的内容。我应该使用 CONNECT BY PRIOR
之类的东西来执行这样的递归函数吗?
SQL 总的来说不是我的菜,更不用说 Oracle 了。我找不到解决这个问题的方法。
谢谢
如果主部门 ID 在部门 table 中根本不存在——而不是因为没有直接雇员而没有出现在结果中,例如——那么你可以使用层次结构查询以获取每个部门的根父级:
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
然后将其用作主查询中的内联视图,而不是直接引用 table:
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
(这会为空)。
您可以使用 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
| 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
| 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 |