【问题标题】:How to get root of hierarchial joined data in oracle 11g如何在 oracle 11g 中获取分层连接数据的根
【发布时间】:2020-08-31 18:41:56
【问题描述】:

我的架构如下所示。

我有等级区:

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 层次结构的底部。如何选择districts 层次结构的 的每个房子和idname

目前我正在使用两个子查询,但感觉不对:

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'                     |
+------------------------------------+

【问题讨论】:

  • 你有样本数据和预期结果吗。
  • SQLFiddle 现在对我不起作用。我会尝试使用 ASCII 表提供示例数据:)

标签: sql oracle oracle11g recursive-query hierarchical-query


【解决方案1】:

我喜欢为此使用递归的with 子句。您正在使用的 Oracle 起始版本 11gR2 支持此功能。我发现与connect by 查询相比,学习这种新语法是值得的,因为:

  • 它基于标准 SQL 规范(所有其他主要数据库都支持 with 子句中的递归)
  • 它比 Oracle 特定的方法更灵活

考虑:

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

【讨论】:

    【解决方案2】:

    您可以使用 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;
    

    db<>fiddle

    您也可以使用递归 CTE 代替分层查询。

    【讨论】:

      【解决方案3】:

      您可以使用 connect_by_root 获取所有分区的根区,并使用 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)
      

      fiddle

      【讨论】:

        猜你喜欢
        • 2016-04-10
        • 2011-05-21
        • 1970-01-01
        • 2012-08-23
        • 1970-01-01
        • 2013-03-07
        • 2021-01-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多