如何在 oracle 11g 中获取分层连接数据的根
How to get root of hierarchial joined data in oracle 11g
我的架构如下所示。
我有等级区:
create table district(
id integer primary key,
name varchar2(32),
parent_id integer references district(id)
)
以及区内房屋:
create table house(
id integer primary key,
name varchar2(32),
district_id integer references district(id)
)
house.district_id
总是 在 district
的层次结构的底部。我如何 select district
层次结构的 root 的每个房屋以及 id
和 name
?
目前我正在使用两个子查询,但感觉不对:
select
h.id,
h.name,
(
select id from district
where parent_id is null
start with id = house.district_id
connect by parent_id = id
) as district_id,
(
select name from district
where parent_id is null
start with id = house.district_id
connect by parent_id = id
) as district_name
from house;
Oracle 版本为 11g 第 2 版。
示例数据:
地区
+-------------------+
| id name parent_id |
+-------------------+
| 1 'one' NULL |
| 2 'two' 1 |
| 3 'three' 3 |
+-------------------+
房子
id name district_id
1 'h1' 3
2 'h2' 3
3 'h3' 3
期望的输出:
+------------------------------------+
| id name district_id, district_name |
+------------------------------------+
| 1 'h1' 1 'one' |
| 2 'h2' 1 'one' |
| 3 'h3' 1 'one' |
+------------------------------------+
而不是有一个(或两个)相关的子查询,您可以使用 connect_by_root()
获取所有地区 ID 及其根 - 然后加入:
with d (root_id, root_name, id) as (
select connect_by_root(id), connect_by_root(name), id
from district
start with parent_id is null
connect by parent_id = prior id
)
select
h.id,
h.name,
d.root_id,
d.root_name
from house h
join d on d.id = h.district_id;
您也可以使用递归 CTE 而不是分层查询。
您可以使用connect_by_root获取所有根分区sub-districts和connect_by_isleaf仅在数据中保留底层分区
select h.id, h.name, d.root_id district_id, d.root_name district_name
from house h
inner join (
select id, root_id, root_name from (
select id, connect_by_root(id) root_id, connect_by_root(name) root_name, connect_by_isleaf is_leaf
from district
start with parent_id is null
connect by prior id = parent_id
)
where is_leaf = 1
) d
on (h.district_id = d.id)
我喜欢为此使用递归 with
子句。您正在使用的 Oracle 起始版本 11gR2 支持此功能。我发现与 connect by
查询相比,学习这种新语法是值得的,因为:
- 它基于标准SQL规范(所有其他主要数据库都在
with
子句中支持递归)
- 它比 Oracle-specific 方法
更灵活
考虑:
with cte (id, parent_id, root_id, root_name) as (
select id, parent_id, id as root_id, name as root_name
from district
where parent_id is null
union all
select d.id, d.parent_id, c.root_id, c.root_name
from cte c
inner join district d on d.parent_id = c.id
) search depth first by id set order1
select h.id, h.name, c.root_id, c.root_name
from house h
inner join cte c on c.id = h.district_id
我的架构如下所示。
我有等级区:
create table district(
id integer primary key,
name varchar2(32),
parent_id integer references district(id)
)
以及区内房屋:
create table house(
id integer primary key,
name varchar2(32),
district_id integer references district(id)
)
house.district_id
总是 在 district
的层次结构的底部。我如何 select district
层次结构的 root 的每个房屋以及 id
和 name
?
目前我正在使用两个子查询,但感觉不对:
select
h.id,
h.name,
(
select id from district
where parent_id is null
start with id = house.district_id
connect by parent_id = id
) as district_id,
(
select name from district
where parent_id is null
start with id = house.district_id
connect by parent_id = id
) as district_name
from house;
Oracle 版本为 11g 第 2 版。
示例数据: 地区
+-------------------+
| id name parent_id |
+-------------------+
| 1 'one' NULL |
| 2 'two' 1 |
| 3 'three' 3 |
+-------------------+
房子
id name district_id
1 'h1' 3
2 'h2' 3
3 'h3' 3
期望的输出:
+------------------------------------+
| id name district_id, district_name |
+------------------------------------+
| 1 'h1' 1 'one' |
| 2 'h2' 1 'one' |
| 3 'h3' 1 'one' |
+------------------------------------+
而不是有一个(或两个)相关的子查询,您可以使用 connect_by_root()
获取所有地区 ID 及其根 - 然后加入:
with d (root_id, root_name, id) as (
select connect_by_root(id), connect_by_root(name), id
from district
start with parent_id is null
connect by parent_id = prior id
)
select
h.id,
h.name,
d.root_id,
d.root_name
from house h
join d on d.id = h.district_id;
您也可以使用递归 CTE 而不是分层查询。
您可以使用connect_by_root获取所有根分区sub-districts和connect_by_isleaf仅在数据中保留底层分区
select h.id, h.name, d.root_id district_id, d.root_name district_name
from house h
inner join (
select id, root_id, root_name from (
select id, connect_by_root(id) root_id, connect_by_root(name) root_name, connect_by_isleaf is_leaf
from district
start with parent_id is null
connect by prior id = parent_id
)
where is_leaf = 1
) d
on (h.district_id = d.id)
我喜欢为此使用递归 with
子句。您正在使用的 Oracle 起始版本 11gR2 支持此功能。我发现与 connect by
查询相比,学习这种新语法是值得的,因为:
- 它基于标准SQL规范(所有其他主要数据库都在
with
子句中支持递归) - 它比 Oracle-specific 方法 更灵活
考虑:
with cte (id, parent_id, root_id, root_name) as (
select id, parent_id, id as root_id, name as root_name
from district
where parent_id is null
union all
select d.id, d.parent_id, c.root_id, c.root_name
from cte c
inner join district d on d.parent_id = c.id
) search depth first by id set order1
select h.id, h.name, c.root_id, c.root_name
from house h
inner join cte c on c.id = h.district_id