3

私は「エレガントに」解決するのに苦労しているOracleの問題に取り組んでいます。

A、B、C の 3 つの異なる識別子を持つデータ抽出があります。

各識別子は複数の行に表示される場合があり、各行にはこれら 3 つの識別子の 1 つまたは複数が含まれる場合があります (つまり、列にデータが入力されているか null である)。

A、B、または C のいずれかの組み合わせを共通に持つすべてのレコードをグループ化し、それらに同じグループ ID を割り当てられるようにしたいと考えています。

最終的なグループがどうあるべきかを示す表を抽出します。

Rownum | A    | B    | C    | End group
1        p      NULL   NULL   1
2        p      r      NULL   1
3        q      NULL   NULL   2
4        NULL   r      NULL   1
5        NULL   NULL   s      2
6        q      NULL   s      2

私の最初のアプローチは、抽出の各行に GUID を割り当て、3 つの識別子のルックアップ テーブルを作成することでした。

GUID | IDENTIFIER | IDENTIFIER TYPE | GROUP | END GROUP
1      p            A                 1       1
2      p            A                 1       1
2      r            B                 2       1
3      q            A                 3       3
4      r            B                 2       1
5      s            C                 4       3
6      q            A                 3       3
6      s            C                 4       3

次に、識別子でグループ化し、グループ番号を割り当てます。ただし、最終グループに示されているビューを提供するには、可能な場合はグループを組み合わせる必要があります。

この問題に対して私が考えることができる唯一の解決策は、ループを使用することですが、これは避けたいと思います。

どんなアイデアでも大歓迎です。

ニール

4

2 に答える 2

4

これは実に興味深い問題です。それでも、「グループ」の定義が欠けていると思います。あなたの例では(p,null,null) (row1)(null,r,null) (row4)は共通の識別子を共有しておらず、同じグループに属しているため、グループ化には次の定義を使用します。

少なくとも 1 つの識別子をこのグループの少なくとも 1 つの行と共有している場合、その行はグループに属しています。

これは、行を「連鎖」できることを意味します。これは当然、階層的なソリューションにつながります。

SQL> SELECT ID, a, b, c, MIN(grp) grp
  2    FROM (SELECT connect_by_root(id) ID,
  3                 connect_by_root(a) a,
  4                 connect_by_root(b) b,
  5                 connect_by_root(c) c,
  6                 ID grp
  7             FROM a
  8           CONNECT BY NOCYCLE(PRIOR a = a
  9                           OR PRIOR b = b
 10                           OR PRIOR c = c))
 11   GROUP BY ID, a, b, c
 12   ORDER BY ID;

        ID A          B          C                 GRP
---------- ---------- ---------- ---------- ----------
         1 p                                         1
         2 p          r                              1
         3 q                                         3
         4            r                              1
         5                       s                   3
         6 q                     s                   3

6 rows selected

サブクエリを実行して、構造を理解できます。

SQL> SELECT connect_by_root(id) ID,
  2         connect_by_root(a) a,
  3         connect_by_root(b) b,
  4         connect_by_root(c) c,
  5         substr(sys_connect_by_path(ID, '->'), 3) path,
  6         ID grp
  7    FROM a
  8  CONNECT BY NOCYCLE(a = PRIOR a
  9                  OR b = PRIOR b
 10                  OR c = PRIOR c);

        ID A          B          C          PATH            GRP
---------- ---------- ---------- ---------- -------- ----------
         1 p                                1                 1
         1 p                                1->2              2
         1 p                                1->2->4           4
         2 p          r                     2                 2
         2 p          r                     2->1              1
         2 p          r                     2->4              4
         3 q                                3                 3
         3 q                                3->6              6
         3 q                                3->6->5           5
         4            r                     4                 4
         4            r                     4->2              2
         4            r                     4->2->1           1
         5                       s          5                 5
         5                       s          5->6              6
         5                       s          5->6->3           3
         6 q                     s          6                 6
         6 q                     s          6->3              3
         6 q                     s          6->5              5

18 rows selected
于 2010-08-04T13:12:17.947 に答える
2

ループの代わりにマージを使用します。

Table a(a,b,c,groupId)

声明:

   merge into a
   USING (SELECT RANK() OVER(ORDER BY a,b,c) g, ROWID rid FROM a) SOURCE
   ON (a.ROWID = SOURCE.rid)
   WHEN MATCHED THEN UPDATE SET a.GroupId = SOURCE.g

それは次と同じです:

    BEGIN
        FOR x IN ( SELECT RANK() OVER(ORDER BY a,b,c) g, ROWID rid FROM a)
        LOOP
             UPDATE a
                SET GroupId  = x.g
             WHERE a.RowId = x.rid;
        END LOOP;
    END;
于 2010-07-28T10:03:42.223 に答える