2017-09-20 8 views
0

を持っている間、私はこのようなテーブルを持っているIDのグループを取得:SQLのORACLEは - パス

ID1 | ID2 
========== 
A | B 
C | B 
A | F 
G | B 
G | E 
J | B 
X | Y 
Z | Y 

が、私はそれを見つける(マーク)別々のグループSQL SELECTを記述する必要があります。この例では、A、B、C、F、G、E、JとX、Y、Zという2つのグループがあります。それは、それらの間の(方向なし)パスを持っているすべてのようなものです(家族関係のような).Thereは、それが文字列になりますどんなに場合、または新しい(LISTAGGまたはパス(例えばまたはCYCLE)BY CONNECT付きで)

ID1 | ID2 | GROUP 
================= 
A | B | 1 
C | B | 1 
A | F | 1 
G | B | 1 
G | E | 1 
J | B | 1 
X | Y | 2 
Z | Y | 2 

[A、Z]と1つ以上の行がある場合、すべての別個の文字が1つのグループです。 私はそれが何かに持っていると思うまたはサイプレス私はそれがどのように見えるか分からない。

+0

最初の2つの行が「X | Y "と" Z | Y " - それはグループ1になりますか?また、物事を明確にするために、列ID1の値が複数回出現する場合、または列ID2の値が2回以上出現した場合最後のステートメントが正しい場合、順序は何ですか;前述したように、最後の2つの行が最初に返された場合、それらはグループ1になりますか? – g00dy

+0

ORDERingは問題ありません。 Y "は最初になり、" Z | Y "は最後であり、それは1つのグループです(グループの番号付けはサンプルであり、GROUP列の値として1,1,2,1,3を持つことができます)。 –

答えて

1

my answer hereから適応:

SQL Fiddle

Oracleの11グラムR2スキーマのセットアップ

CREATE TABLE ids (ID1, ID2) AS 
    SELECT 'A', 'B' FROM DUAL UNION ALL 
    SELECT 'C', 'B' FROM DUAL UNION ALL 
    SELECT 'A', 'F' FROM DUAL UNION ALL 
    SELECT 'G', 'B' FROM DUAL UNION ALL 
    SELECT 'G', 'E' FROM DUAL UNION ALL 
    SELECT 'J', 'B' FROM DUAL UNION ALL 
    SELECT 'X', 'Y' FROM DUAL UNION ALL 
    SELECT 'Z', 'Y' FROM DUAL; 

クエリ1

WITH indexed_ids (id, id1, id2) AS (
    SELECT ROWNUM, id1, id2 FROM ids 
), 
grouped_ids (id, id1, id2, min_id) AS (
    SELECT i.*, 
     LEAST(
      MIN(id) OVER (PARTITION BY id1), 
      MIN(id) OVER (PARTITION BY id2) 
     ) AS min_id 
    FROM indexed_ids i 
) 
SELECT id, id1, id2, 
     MIN("GROUP") AS "GROUP" 
FROM (
    SELECT id, id1, id2, 
     CONNECT_BY_ROOT(id) AS "GROUP" 
    FROM grouped_ids g 
    START WITH id = min_id 
    CONNECT BY NOCYCLE (PRIOR id1 IN (id1, id2) OR PRIOR id2 IN (id1, id2)) 
) 
GROUP BY id, id1, id2 
ORDER BY id 

Results

| ID | ID1 | ID2 | GROUP | 
|----|-----|-----|-------| 
| 1 | A | B |  1 | 
| 2 | C | B |  1 | 
| 3 | A | F |  1 | 
| 4 | G | B |  1 | 
| 5 | G | E |  1 | 
| 6 | J | B |  1 | 
| 7 | X | Y |  7 | 
| 8 | Z | Y |  7 | 

GROUP列は、グループの最小IDを識別する。シーケンシャルな場合は、GROUPを、DENSE_RANK()の解析関数を使用できます。

1

私はあなたがここにconnect_by_rootを使用できると思う:

select id1, listagg(root) within group (order by root) list 
    from (select distinct id1, root 
      from (select t.*, connect_by_root(id1) root 
        from (select id1, id2 from t union select id2, id1 from t) t 
        connect by nocycle prior id1 = id2)) 
    group by id1 

は...私達を与える:

A ABCEFGJ 
B ABCEFGJ 
C ABCEFGJ 
E ABCEFGJ 
F ABCEFGJ 
G ABCEFGJ 
J ABCEFGJ 
X XYZ 
Y XYZ 
Z XYZ 

残りはdense_rank()を使用して、元のテーブルと結合する、シンプルです:

with t(id1, id2) as (
    select 'A', 'B' from dual union all 
    select 'C', 'B' from dual union all 
    select 'A', 'F' from dual union all 
    select 'G', 'B' from dual union all 
    select 'G', 'E' from dual union all 
    select 'J', 'B' from dual union all 
    select 'X', 'Y' from dual union all 
    select 'Z', 'Y' from dual), 
q as (
    select id1, listagg(root) within group (order by root) list 
     from (select distinct id1, root 
       from (select t.*, connect_by_root(id1) root 
         from (select id1, id2 from t union select id2, id1 from t) t 
         connect by nocycle prior id1 = id2)) 
     group by id1) 
select id1, id2, dense_rank() over (order by list) grp 
    from t join q using (id1) 

結果:

ID1 ID2  GRP 
--- --- ---------- 
A F   1 
A B   1 
C B   1 
G E   1 
J B   1 
G B   1 
X Y   2 
Z Y   2 
8 rows selected 
関連する問題