sql >> データベース >  >> RDS >> Oracle

カンマ区切りの値をOracleの行に変換するにはどうすればよいですか?

    これは本当に悪いデザインであることに同意します。そのデザインを変更できない場合は、これを試してください:

    select distinct id, trim(regexp_substr(value,'[^,]+', 1, level) ) value, level
      from tbl1
       connect by regexp_substr(value, '[^,]+', 1, level) is not null
       order by id, level;
    

    OUPUT

    id value level
    1   AA  1
    1   UT  2
    1   BT  3
    1   SK  4
    1   SX  5
    2   AA  1
    2   UT  2
    2   SX  3
    3   UT  1
    3   SK  2
    3   SX  3
    3   ZF  4
    

    これへのクレジット

    よりエレガントで効率的な方法で重複を削除するには(@mathguyのクレジット)

    select id, trim(regexp_substr(value,'[^,]+', 1, level) ) value, level
      from tbl1
       connect by regexp_substr(value, '[^,]+', 1, level) is not null
          and PRIOR id =  id 
          and PRIOR SYS_GUID() is not null  
       order by id, level;
    

    「ANSIer」アプローチが必要な場合は、CTEを使用してください:

    with t (id,res,val,lev) as (
               select id, trim(regexp_substr(value,'[^,]+', 1, 1 )) res, value as val, 1 as lev
                 from tbl1
                where regexp_substr(value, '[^,]+', 1, 1) is not null
                union all           
                select id, trim(regexp_substr(val,'[^,]+', 1, lev+1) ) res, val, lev+1 as lev
                  from t
                  where regexp_substr(val, '[^,]+', 1, lev+1) is not null
                  )
    select id, res,lev
      from t
    order by id, lev;
    

    出力

    id  val lev
    1   AA  1
    1   UT  2
    1   BT  3
    1   SK  4
    1   SX  5
    2   AA  1
    2   UT  2
    2   SX  3
    3   UT  1
    3   SK  2
    3   SX  3
    3   ZF  4
    

    MT0による別の再帰的アプローチですが、正規表現はありません:

    WITH t ( id, value, start_pos, end_pos ) AS
      ( SELECT id, value, 1, INSTR( value, ',' ) FROM tbl1
      UNION ALL
      SELECT id,
        value,
        end_pos                    + 1,
        INSTR( value, ',', end_pos + 1 )
      FROM t
      WHERE end_pos > 0
      )
    SELECT id,
      SUBSTR( value, start_pos, DECODE( end_pos, 0, LENGTH( value ) + 1, end_pos ) - start_pos ) AS value
    FROM t
    ORDER BY id,
      start_pos;
    

    30000行のデータセットで3つのアプローチを試し、118104行が返され、次の平均結果が得られました。

    • 私の再帰的アプローチ:5秒
    • MT0アプローチ:4秒
    • マスガイアプローチ:16秒
    • MT0再帰的アプローチの正規表現なし:3.45秒

    @Mathguyは、より大きなデータセットでもテストしました:

    すべての場合において、再帰クエリ(regularsubstrとinstrを使用したクエリのみをテストしました)の方が2〜5倍優れています。これは、文字列あたりの文字列/トークンの数と、階層型と再帰型、階層型のCTAS実行時間の組み合わせです。 。常に秒単位

    • 30,000 x 4:5/1。
    • 30,000 x 10:15/3。
    • 30,000 x 25:56/37。
    • 5,000 x 50:33/14。
    • 5,000 x 100:160/81。
    • 10,000 x 200:1,924 / 772


    1. PostgreSQLでUPSERT(MERGE、INSERT ... ON DUPLICATE UPDATE)する方法は?

    2. Oracleの数値を含む行を返す

    3. phpがpostgresqlで動作するようにするにはどうすればよいですか?

    4. SQLiteケース