0

私はテーブルを持っています: Table_1 は次のようになります:

id   |   column1
-----------------
10   |   abc, kdm
20   |   xyz, lop, nkk

私が欲しいのは、テーブルを次のように変換することです:

id   |   column1
-----------------
10   |   abc
10   |   kdm
20   |   xyz 
20   |   lop
20   |   nkk

これを行うには、次のようなクエリを使用しました。

select id, regexp_substr(column1,'[^,]+', 1, level) from Table_1 
connect by regexp_substr(column1, '[^,]+', 1, level) is not null;

このクエリは、カンマ区切りの値の数が少ない限り正常に機能します。しかし、それが大きくなると、処理にますます時間がかかります。

私が思いついた解決策の 1 つは、別のテーブルを作成し、Table_1 の値を繰り返し処理して値を挿入することでした。

疑似コードは次のとおりです。

FOR r in each row
    FOR i in 1..length(comma_separated_values)
       insert into new_table values(id, select regexp_substr(column1,'[^,]+', 1, i) from Table_1 
    End LOOP;
End LOOP;

しかし、これもカンマ区切りの値が大きくなるにつれて多くの時間を消費するため、これを行うための他の最適な方法はありますか (別のテーブルを使用しないことをお勧めしますが、一時/仮想テーブルは問題ありません)。

私はOracle SQLを使用しています。

前もって感謝します。

4

3 に答える 3

1

明らかに、根本的な問題を修正するためのランディの提案は理想的です。それが不可能な場合は、さまざまなオプションを利用できます。多くはここにリストされています 。一般に、パフォーマンスを向上させる簡単な解決策は、column1 の値の最大数を見つけ、その数の列を持つ一時テーブルを作成し、その一時テーブルを目的の形式に変換することです。つまり、テーブルが次のように見える中間ステップがありますid|val1|val2|val3|..|valn

于 2015-08-31T19:31:22.667 に答える
1

正規化の問題にもかかわらず、元のクエリは実際には機能しません。テスト データで実行すると、次のようになります。

SQL> with Table_1(id, column1) as (
  2    select 10, 'abc, kdm' from dual
  3    union
  4    select 20, 'xyz, lop, nkk' from dual
  5  )
  6  select id, regexp_substr(column1,'[^,]+', 1, level) from Table_1
  7  connect by regexp_substr(column1, '[^,]+', 1, level) is not null;

        ID REGEXP_SUBSTR
---------- -------------
        10 abc
        10  kdm
        20  nkk
        20  lop
        20  nkk
        20 xyz
        10  kdm
        20  nkk
        20  lop
        20  nkk

10 rows selected.

SQL>

そのため、さらに値を追加すると、問題が指数関数的に増大し、パフォーマンスが低下します。3 行目を追加してテストします。また、区切り文字はコンマだけでなく、コンマスペースです。 また、リストの解析に使用される正規表現形式('[^,]+')は null では機能しないため、避ける必要があります。残念ながら、これはリストを解析するための答えとして与えられる最も一般的な正規表現です。

代わりにこれを試してみてください。より大きなリストを簡単に処理できるはずです。

SQL> with Table_1(id, column1) as (
     select 10, 'abc, kdm' from dual
     union
     select 20, 'xyz, lop, nkk' from dual
   )
   SELECT id, -- column1,
              --  COLUMN_VALUE AS match_nbr,
          REGEXP_SUBSTR( column1 ,'(.*?)(, |$)', 1, COLUMN_VALUE, NULL, 1 ) AS match_value
   FROM
     Table_1,
     TABLE(
       CAST(
         MULTISET(
           SELECT LEVEL
           FROM   DUAL
           CONNECT BY LEVEL <= REGEXP_COUNT(column1 , ',' )+1
         ) AS SYS.ODCINUMBERLIST
       )
     );

        ID MATCH_VALUE
---------- -------------
        10 abc
        10 kdm
        20 xyz
        20 lop
        20 nkk

SQL>

基本的に、これはリスト内の要素数 (要素番号を含む) のテーブルを 1 行に 1 行作成し、それをメイン テーブルと結合します。
COLUMN_VALUE 値行のコメントを外して、要素の番号付けを確認します。データにコンマが含まれていないことを前提としています。

于 2015-08-31T20:04:31.357 に答える