Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Bagaimana cara mengubah nilai yang dipisahkan koma menjadi baris di Oracle?

Saya setuju bahwa ini adalah desain yang sangat buruk. Coba ini jika Anda tidak dapat mengubah desain itu:

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;

KELUARKAN

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

Penghargaan untuk ini

Untuk menghapus duplikat dengan cara yang lebih elegan dan efisien (kredit ke @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;

Jika Anda menginginkan pendekatan "ANSIer", gunakan 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;

KELUARAN

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

Pendekatan rekursif lain oleh MT0 tetapi tanpa regex:

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;

Saya telah mencoba 3 pendekatan dengan set data 30000 baris dan 118104 baris kembali dan mendapatkan hasil rata-rata berikut:

  • Pendekatan rekursif saya:5 detik
  • Pendekatan MT0:4 detik
  • Pendekatan Mathguy:16 detik
  • Pendekatan rekursif MT0 tanpa ekspresi reguler:3,45 detik

@Mathguy juga telah menguji dengan kumpulan data yang lebih besar:

Dalam semua kasus, kueri rekursif (saya hanya menguji satu dengan substr dan instr reguler) lebih baik, dengan faktor 2 hingga 5. Berikut adalah kombinasi # string / token per string dan waktu eksekusi CTAS untuk hierarki vs. rekursif, hierarki terlebih dahulu . Semua waktu dalam hitungan detik

  • 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Akses layanan Web dari prosedur tersimpan Oracle

  2. Oracle Setelah Hapus Pemicu... Bagaimana cara menghindari Mutasi Tabel (ORA-04091)?

  3. Oracle PL/SQL - Tingkatkan Pengecualian Buatan Pengguna Dengan SQLERRM Kustom

  4. Oracle:Kinerja Kumpulkan Massal

  5. Dapatkan BLOB dari Kolom BFILE di Oracle