4

アカウント テーブル:

      ID_ACC    PARENT_ACC
        76543    76543      <-edit
        18252    76543
        34456    76543
        456567   76543
        457564   65424
        45654242 6556756

情報テーブル:

      ID     account_id  product_id
    875621     18252       98567
    875621     34456       98567

製品表:

    ACCOUNTID  PRODUCT_ID 
      456452     98567

アカウント テーブルには、アカウントの ID が含まれます。ただし、一部のアカウント ( ID_ACC ) には親アカウント ( Parent_acc ) があります。この例では、

ID_ACC:   18252,
          34456,
          456567 

同じparent_acc(76543)があります。

一部の子には情報があります (情報テーブル)

(この例では、1825234456が情報テーブルに接続されていることを示しています)

次に、いくつかの info.account_id に製品 (Product テーブル) が含まれています (この例では、18252 accountid のみがアカウント番号: 456452を持つ製品を持っています)。

Account.id_acc=Info.account_id
Info.product_id=Product_id.product_id

すべてのアカウント階層を選択したい:

76543,
18252,
34456,
456567,
456452.

(私にとって)最も難しいことは、(表示するために)テーブルに基づいている必要があることです。to_showテーブルが次のように入力されている場合。34456 アカウントの出力は、上記のリストと同じである必要があります。

to_show テーブルが次のように入力されている場合。「76543,18252,34456」の場合、上記と同じ状況など...

私が必要とするのは、to_show テーブルにあるアカウント (製品テーブルまたは情報またはアカウント) に関係なく、すべての階層を表示することです...入力として、製品テーブルから子/親またはアカウントを取得できます。私はそれをやろうとしていましたが、残念ながら私には難しすぎます (私は階層クエリの初心者なので..)。みんな、私を助けてくれませんか?

create table account (
id_acc number,
parent_acc number
)
;
create table info
(
ID number,
Account_id number,
Product_id number
);
create table product (
Account_id number,
product_id number
);
create table to_show (
ID number
);
insert into account (id_acc,parent_acc)) values (76543,76543);
insert into account (id_acc,parent_acc) values (18252,76543);
insert into account (id_acc,parent_acc) values (34456,76543);
insert into account (id_acc,parent_acc) values (456567,76543);
insert into account (id_acc,parent_acc) values (457564,65424);
insert into account (id_acc,parent_acc) values (45654242,6556756);
insert into info values (875621,18252,98567);
insert into info values (875621,34456,null);
insert into product values (456452,98567);
insert into to_show values (34456);
4

1 に答える 1

3

アプローチは、最初に欠落している階層productinfo考慮して結合し、次に結果を生成することです...階層Productinfo関連するデータがあるため、それらを結合する必要があります。おそらくここが一番苦労した部分だと思います。すべての階層データが 1 か所にあるわけではありません。そのことに気づいたとき、仕事の前に連絡できるようにするための組合の必要性が生まれました。

したがって、結合productinfoて必要な追加の階層データを取得し、これを account テーブルに結合します。これにより、必要なすべての親子関係を含むデータセットが作成されます。

その後、 を使用connect by priorして階層をトラバースできます。

SELECT a.id_acc, level as lvl
FROM (SELECT id_acc, parent_acc FROM account 
      UNION 
      SELECT P.Account_ID, i.account_id  FROM info i
      INNER JOIN product p 
       on I.Product_ID=P.Product_ID) A
START WITH A.ID_ACC=76543
CONNECT BY prior  a.id_acc=a.parent_acc

これは以下を返します:

Account Lvl
76543   1
18252   2
456452  3
34456   2
456567  2

注: 456452 は 18252 の下に存在するため、階層からの関係が維持されます。76543 には 3 つの子 (18252、34456、456567) があり、18252 には子 456452 があることを意味します。

あなたの質問に関するいくつかの仮定を考えると、これが私が思いつくことができる最善のものだと思います。

フル パスを知る必要がある場合( )、またはsys_connect_by_path削除する必要があるデータにループがある場合 ( nocycle) または isLeaf ( connect_by_isLeaf) で階層内の子のないレコードを表示する必要がある場合は、その他の機能をいくつか追加できます。

SELECT a.id_acc
     , level as lvl
     , SYS_CONNECT_BY_PATH(ID_Acc, '/') "Path"
     , CONNECT_BY_ISLEAF "IsLeaf"
FROM (SELECT id_acc, parent_acc FROM account 
      UNION
      SELECT P.Account_ID, i.account_id  
      FROM info i
      INNER JOIN product p 
        on I.Product_ID=P.Product_ID) A
START WITH a.id_acc=76543
CONNECT BY nocycle prior a.id_acc=a.parent_acc

これにより、次のような結果になります。

ID_acc  lvl Path                  isLeaf
76543   1   /76543                0
18252   2   /76543/18252          0
456452  3   /76543/18252/456452   1
34456   2   /76543/34456          1
456567  2   /76543/456567         1

機能の完全なリストについては、Oracle Docsを参照してください。

を使用して、データにループがないことの重要性を軽視しましたnocycle。データにループが存在する場合、結果が正しくない可能性があります。

もう少し作業すれば、to_Show に関係するトップ レベルを特定できます。

select distinct ID_ACC
from (SELECT id_acc, parent_acc FROM account 
      UNION
      SELECT P.Account_ID, i.account_id  
      FROM info i
      inner join product p 
        on i.product_id=p.product_id) a
where parent_acc is null
connect by  prior a.parent_acc = a.id_acc
start with id_acc in (select id from to_show)

それを上記と組み合わせて、ハードコーディングなしで目的の結果を達成します。

SELECT a.id_acc
     , level as lvl
     , SYS_CONNECT_BY_PATH(ID_Acc, '/') "Path"
     , connect_by_isleaf "IsLeaf"
FROM (SELECT id_acc, parent_acc FROM account 
      UNION
      SELECT P.Account_ID, i.account_id  
      FROM info i
      INNER JOIN product p 
        on i.product_id=p.product_id) a
connect by nocycle prior a.id_acc=a.parent_acc
start with id_acc in 
(
select distinct ID_ACC
from (SELECT id_acc, parent_acc FROM account 
      UNION
      SELECT P.Account_ID, i.account_id  
      FROM info i
      inner join product p 
        on i.product_id=p.product_id) a
where parent_acc is null
connect by  prior a.parent_acc = a.id_acc
start with id_acc in (select id from to_show))

ここで行ったのは、サブクエリで start with を使用して to_Show の各レコードのトップ レベル ドメインを取得し、関係を逆にして、ツリーを下ではなく上にクロールし、その個別のトップ レベル ドメインを使用して全体を返すことだけでした。階層; したがって、to_show でノードを表示します。そしてそれが存在する階層全体。

ここに画像の説明を入力

または、重複を排除するための読みやすさとリファクタリングのための CTE (Common Table Expression) として。

with 
--Let's combine the hierarchies so they are all in one place.
hsource as (
   select id_acc, parent_acc from account 
   UNION
   SELECT P.Account_ID, i.account_id  
   FROM info i
   inner join product p 
   on i.product_id=p.product_id),
--Now lets get the top domain or root nodes of each item in To_Show
top_domain as (
   select distinct id_acc  
   from (hSource) a
   where parent_acc is null  --this null compare is actually what tells us it's a root/Top domain!  Assumption being all roots have null parent_Acc!
   connect by  prior a.parent_acc = a.id_acc
   start with id_acc in (select id from to_show))
--Now lets use those top domains or root notes to render the hierarchy of each.
SELECT a.id_acc
     , level as lvl
     , SYS_CONNECT_BY_PATH(ID_Acc, '/') "Path"
     , connect_by_isleaf "IsLeaf"
FROM (Select id_acc, parent_acc from hSource) a
connect by nocycle prior a.id_acc=a.parent_acc
start with id_acc in  (Select ID_ACC from Top_Domain)

最後に... が null であるという私の仮定parent_Accが正しくない場合は、top_domain のクエリを以下に変更する必要があります。 Connect by priorトップ レベルが null になると想定している場合は、ループ データを取得するため、単純に設定できないa.ID_ACC=a.parent_Accしたがって、case ステートメントを使用して 2 つのステートメント データを変更し、Parent_ACC is nulla を真のステートメントにするだけです。技術的にはwhere節はそのままでもいいのですがID_ACC=parent_Acc、テーマを守りたかったのです。ただし、行は変更する必要がありconnect by priorます上記でデータにループがないと言ったことを思い出してください...まあ、ID_ACC=parent_ACCそれがループを引き起こすとき。つまり、さあ!どうすれば自分の親になれますか? しかし、case ステートメントを使用して処理しました。

with 
--Let's combine the hierarchies so they are all in one place.
hsource as (
   select id_acc, parent_acc from account 
   UNION
   SELECT P.Account_ID, i.account_id  
   FROM info i
   inner join product p 
   on i.product_id=p.product_id),
--Now lets get the top domain or root nodes of each item in To_Show
top_domain as (
   select distinct a.id_acc
   from (hsource) a
--Modification starts here...
   where case when  a.parent_acc =a.id_Acc then null else a.parent_Acc end is null
   connect by prior (case when a.parent_acc=a.id_acc then null else a.parent_Acc end) = a.id_acc
--ends here
   start with a.id_acc in (select id from to_show))
--Now lets use those top domains or root notes to render the hierarchy of each.
    SELECT a.id_acc
         , level as lvl
         , SYS_CONNECT_BY_PATH(ID_Acc, '/') "Path"
         , connect_by_isleaf "IsLeaf"
    FROM (Select id_acc, parent_acc from hSource) a
    connect by nocycle prior a.id_acc=a.parent_acc
    start with id_acc in  (Select ID_ACC from Top_Domain)
于 2015-11-23T16:46:46.117 に答える