3

編集:サブクエリを使用しようとした理由を明確にするために、場所エンティティを導入して追加情報を提供しました

Oracle 11gデータベースには、最終的に数百万行を含む要素の階層構造テーブルがあります。各行には、その親を指すインデックス付きの外部キーがあり、循環は許可されていません。要素には名前と型もあります。それに加えて、要素に似た別のエンティティーlocationがあります(階層型で、親 + 名前を指す外部キーがあります)。最上位の要素(あなたのルート) は場所にあります(それらはLocationIdによって接続されています)。したがって、2 つのエンティティがあります。

位置:

  • ID [NUMBER(9,0), PK]
  • ParentId [NUMBER(9,0), FK]
  • 名前 [VARCHAR2(200)]

エレメント:

  • ID [NUMBER(9,0), PK]
  • LocationId [NUMBER(9,0), FK]
  • ParentId [NUMBER(9,0), FK]
  • TypeId [NUMBER(9,0), FK]
  • 名前 [VARCHAR2(200)]

たとえば、テーブルに次のデータが含まれているとします。

位置:

Id   | ParentId | Name
----------------------------------
100  |   null   | TopLocation
101  |   100    | Level1Location
102  |   101    | Level2Location    

エレメント:

Id | LocationId | ParentId | TypeId | Name
----------------------------------------------------
1  |    102     |   null   |    10  | TopParent
2  |   null     |     1    |    11  | Level1Child
3  |   null     |     2    |    11  | Level2Child

私がしなければならないのは、要素のクエリを作成することです。これは、基本的な 4 つの要素列に加えて、親 ID、名前、および型 ID のフル パス + 最上位の要素の 場所ID と名前のフル パスも返します。したがって、 ID 3 の要素を取得した場合(この条件は、ここで指定されていない複数の列によって複雑になる場合もあります)、クエリは次のように返す必要があります。

Id | ParentId | TypeId | Name        | IdsPath | TypeIdsPath | NamesPath                           | LocIdsPath   | LocNamesPath
---------------------------------------------------------------------------------------------------------------------------------------------------------------
3  |    2     |    11  | Level2Child | /3/2/1  |   /11/11/10 |  /Level2Child/Level1Child/TopParent | /102/101/100 | /Level2Location/Level1Location/TopLocation

最初に、場所要素の目的のパスを返すオラクルの階層クエリを作成しました

位置

select
    SYS_CONNECT_BY_PATH(Id, '/') IdsPath,
    SYS_CONNECT_BY_PATH(Name, '/') NamesPath
from 
    loc
where
     connect_by_isleaf = 1
CONNECT BY PRIOR ParentId = e.Id
start with Id = 102

エレメント

select
    SYS_CONNECT_BY_PATH(Id, '/') IdsPath,
    SYS_CONNECT_BY_PATH(TypeId, '/') TypeIdsPath,
    SYS_CONNECT_BY_PATH(Name, '/') NamesPath
from 
    ele
where
     connect_by_isleaf = 1
CONNECT BY PRIOR ParentId = e.Id
start with Id = 3

これらのクエリを基本選択で結合されたサブクエリとして使用したいときに問題が発生しました-階層クエリは完全なテーブルスキャンを実行するため、開始条件を結合条件に置き換えることはできません:

select
    e.*,
    elePath.IdsPath,
    elePath.TypeIdsPath,
    elePath.NamesPath,
    locPath.IdsPath as LocIdsPath,
    locPath.NamesPath as LocNamesPath
from
    ele e
    left join (
        --full table scan!
        select
            CONNECT_BY_ROOT(Id) Id,
            Id as TopEleId,
            SYS_CONNECT_BY_PATH(Id, '/') IdsPath,
            SYS_CONNECT_BY_PATH(TypeId, '/') TypeIdsPath,
            SYS_CONNECT_BY_PATH(Name, '/') NamesPath
        from ele
        where
             connect_by_isleaf = 1
        CONNECT BY PRIOR ParentId = e.Id
    ) elePath on elePath.Id = e.Id
    left join (
        --full table scan!
        select
            CONNECT_BY_ROOT(Id) Id,
            SYS_CONNECT_BY_PATH(Id, '/') IdsPath,
            SYS_CONNECT_BY_PATH(Name, '/') NamesPath
        from loc
        where
             connect_by_isleaf = 1
        CONNECT BY PRIOR ParentId = e.Id
    ) locPath on locPath.Id = elePath.TopEleId
where
    e.Id = 3

クエリは1つだけでなく複数のパスを返す必要があるため、スカラーサブクエリも実行できません。助言がありますか?私は正しい方向に進んでいますか、それとも要素テーブルにいくつかのフィールドを追加し、必要なすべてのパスをキャッシュする必要がありますか? (頻繁に更新されるわけではありません)

ありがとう!

4

1 に答える 1

3

階層構造を逆方向にトラバースし、単純にconnect_by_root()演算子を使用してルート行の列値を取得します。

clear screen;
column IdPath format a11;
column TypeIdPathformat a11
column NamePath format a35;

with t1(id1, parent_id, type_id, Name1) as(
  select 1, null, 10, 'TopParent' from dual union all
  select 2, 1   , 11, 'Level1Child' from dual union all
  select 3, 2   , 11, 'Level2Child' from dual
)
select connect_by_root(id1)                as id1
     , connect_by_root(parent_id)          as ParentId
     , connect_by_root(type_id)            as Typeid
     , connect_by_root(name1)              as name1
     , sys_connect_by_path(id1, '/')       as IdPath
     , sys_connect_by_path(type_id, '/')   as TypeIdPath
     , sys_connect_by_path(name1, '/')     as NamePath 
 from t1
where connect_by_isleaf = 1
start with id1 = 3
connect by id1 = prior parent_id

結果:

 id1 ParentId TypeId  Name1        IdPath  TypeIdPath NamePath                         
 ---------------------------------------------------------------------------       
 3        2      11   Level2Child /3/2/1  /11/11/10  /Level2Child/Level1Child/TopParent

編集#1

目的の出力を取得する 1 つの方法は、スカラー サブクエリを使用することです。

with Locations(Id1, ParentId, Name1) as(
  select 100,  null, 'TopLocation' from dual union all
  select 101,  100 , 'Level1Location' from dual union all
  select 102,  101 , 'Level2Location' from dual
),
elements(id1, LocationId, parent_id, type_id, Name1) as(
  select 1, 102,  null, 10, 'TopParent' from dual union all
  select 2, null, 1   , 11, 'Level1Child' from dual union all
  select 3, null, 2   , 11, 'Level2Child' from dual
)
select e.*
     , (select sys_connect_by_path(l.id1, '/')
          from locations l
          where connect_by_isleaf = 1
          start with l.id1 = e.locationid
          connect by l.id1 = prior parentid)        as LocIdPath
     , (select sys_connect_by_path(l.name1, '/')
          from locations l
          where connect_by_isleaf = 1
          start with l.id1 = e.locationid
          connect by l.id1 = prior parentid)        as LocNamePath
  from ( select connect_by_root(id1)                as id1
              , connect_by_root(parent_id)          as ParentId
              , connect_by_root(type_id)            as Typeid
              , connect_by_root(name1)              as name1
              , sys_connect_by_path(id1, '/')       as IdPath
              , sys_connect_by_path(type_id, '/')   as TypeIdPath
              , sys_connect_by_path(name1, '/')     as NamePath  
              , locationid
          from elements
         where connect_by_isleaf = 1
         start with id1 = 3
       connect by id1 = prior parent_id ) e 

結果:

ID1   PARENTID     TYPEID NAME1       IDPATH      TYPEIDPATH  NAMEPATH                            LOCATIONID LOCIDPATH     LOCNAMEPATH                               
---------- ---------- ----------- ----------- ----------- ----------------------------------- ---------- ------------- -------------------------------------------
  3          2         11 Level2Child /3/2/1      /11/11/10   /Level2Child/Level1Child/TopParent         102 /102/101/100  /Level2Location/Level1Location/TopLocation  
于 2014-03-02T12:17:55.277 に答える