Saya tahu ini telah dijawab sampai tingkat tertentu dengan PHP dan MYSQL, tetapi saya bertanya-tanya apakah seseorang dapat mengajari saya pendekatan paling sederhana untuk membagi string (dipisahkan koma) menjadi beberapa baris di Oracle 10g (lebih disukai) dan 11g.
Tabelnya adalah sebagai berikut:
Name | Project | Error
108 test Err1, Err2, Err3
109 test2 Err1
Saya ingin membuat yang berikut ini:
Name | Project | Error
108 Test Err1
108 Test Err2
108 Test Err3
109 Test2 Err1
Saya telah melihat beberapa solusi potensial di sekitar tumpukan, namun mereka hanya menyumbang satu kolom (menjadi string yang dipisahkan koma). Bantuan apa pun akan sangat dihargai.
REGEXP
,XMLTABLE
danMODEL
klausa, lihat Memisahkan string yang dipisahkan koma dalam tabel menggunakan Oracle SQLJawaban:
Ini mungkin cara yang lebih baik (juga dengan regexp dan terhubung dengan):
EDIT : Berikut adalah penjelasan sederhana (seperti, "tidak mendalam") dari kueri.
length (regexp_replace(t.error, '[^,]+')) + 1
digunakanregexp_replace
untuk menghapus apa pun yang bukan pembatas (dalam hal ini koma) danlength +1
untuk mendapatkan berapa banyak elemen (kesalahan) yang ada.The
select level from dual connect by level <= (...)
menggunakan permintaan hirarkis untuk membuat kolom dengan peningkatan jumlah pertandingan yang ditemukan, dari 1 sampai jumlah total kesalahan.Pratinjau:
table(cast(multiset(.....) as sys.OdciNumberList))
melakukan beberapa casting jenis oracle.cast(multiset(.....)) as sys.OdciNumberList
transformasi beberapa koleksi (satu koleksi untuk setiap baris dalam kumpulan data asli) menjadi koleksi tunggal nomor, OdciNumberList.table()
fungsi mengubah koleksi ke resultset.FROM
tanpa gabungan membuat gabungan silang antara dataset Anda dan multiset. Akibatnya, baris dalam kumpulan data dengan 4 kecocokan akan berulang 4 kali (dengan peningkatan angka di kolom bernama "nilai_kolom").Pratinjau:
trim(regexp_substr(t.error, '[^,]+', 1, levels.column_value))
menggunakancolumn_value
sebagai parameter nth_appearance / ocurrence untukregexp_substr
.t.name, t.project
sebagai contoh) untuk memudahkan visualisasi.Beberapa referensi ke dokumen Oracle:
sumber
'[^,]+'
untuk mengurai string tidak mengembalikan item yang benar jika ada elemen null dalam daftar. Lihat di sini untuk info lebih lanjut: stackoverflow.com/questions/31464275/…regexp_count(t.error, ',')
alih-alihlength (regexp_replace(t.error, '[^,]+'))
, yang dapat membawa peningkatan kinerja lainekspresi reguler adalah hal yang luar biasa :)
sumber
Name
s terhubung, yang dapat dilihat jika Anda menghapusdistinct
. Sayangnya menambahkanand Name = prior Name
keconnect by
penyebab klausaORA-01436: CONNECT BY loop in user data
.ORA-01436
kesalahan dengan menambahkanAND name = PRIOR name
(atau apa pun kunci utama) danAND PRIOR SYS_GUID() IS NOT NULL
Ada perbedaan besar antara keduanya:
Jika Anda tidak membatasi baris, klausa CONNECT BY akan menghasilkan beberapa baris dan tidak akan memberikan keluaran yang diinginkan.
Selain Ekspresi Reguler , beberapa alternatif lain menggunakan:
Mempersiapkan
Menggunakan XMLTABLE :
Menggunakan klausa MODEL :
sumber
('"' || REPLACE(text, ',', '","') || '"')
dan tanda kurung tidak bisa dihilangkan? Dokumen Oracle ([ docs.oracle.com/database/121/SQLRF/functions268.htm ) tidak jelas bagi saya. Apakah ituXQuery_string
?Beberapa contoh lagi yang sama:
Juga, dapat menggunakan DBMS_UTILITY.comma_to_table & table_to_comma: http://www.oracle-base.com/articles/9i/useful-procedures-and-functions-9i.php#DBMS_UTILITY.comma_to_table
sumber
comma_to_table()
hanya berfungsi dengan token yang sesuai dengan konvensi penamaan objek database Oracle. Ini akan terlempar pada string seperti'123,456,789'
misalnya.Saya ingin mengusulkan pendekatan yang berbeda menggunakan fungsi tabel PIPELINED. Ini agak mirip dengan teknik XMLTABLE, kecuali Anda menyediakan fungsi kustom Anda sendiri untuk memisahkan string karakter:
Hasil:
Masalah dengan jenis pendekatan ini adalah sering kali pengoptimal tidak mengetahui kardinalitas fungsi tabel dan harus membuat perkiraan. Ini bisa berpotensi membahayakan rencana eksekusi Anda, jadi solusi ini dapat diperpanjang untuk menyediakan statistik eksekusi untuk pengoptimal.
Anda dapat melihat estimasi pengoptimal ini dengan menjalankan EXPLAIN PLAN pada kueri di atas:
Meskipun koleksi hanya memiliki 3 nilai, pengoptimal memperkirakan 8168 baris untuknya (nilai default). Ini mungkin tampak tidak relevan pada awalnya, tetapi mungkin cukup bagi pengoptimal untuk memutuskan rencana yang kurang optimal.
Solusinya adalah dengan menggunakan ekstensi pengoptimal untuk memberikan statistik pengumpulan:
Menguji rencana eksekusi yang dihasilkan:
Seperti yang Anda lihat, kardinalitas pada denah di atas bukanlah nilai tebakan 8196 lagi. Itu masih tidak benar karena kita mengirimkan kolom alih-alih string literal ke fungsi.
Beberapa penyesuaian pada kode fungsi akan diperlukan untuk memberikan perkiraan yang lebih dekat dalam kasus khusus ini, tetapi saya pikir konsep keseluruhan cukup banyak dijelaskan di sini.
Fungsi str2tbl yang digunakan dalam jawaban ini pada awalnya dikembangkan oleh Tom Kyte: https://asktom.oracle.com/pls/asktom/f?p=100:11 WindowsFAQ.ru::::P11_QUESTION_ID:110612348061
Konsep mengaitkan statistik dengan jenis objek dapat dieksplorasi lebih lanjut dengan membaca artikel ini: http://www.oracle-developer.net/display.php?id=427
Teknik yang dijelaskan di sini bekerja dalam 10g +.
sumber
REGEXP_COUNT tidak ditambahkan hingga Oracle 11i. Berikut adalah solusi Oracle 10g, yang diadopsi dari solusi Art.
sumber
Mulai dari Oracle 12c, Anda dapat menggunakan
JSON_TABLE
danJSON_ARRAY
:Dan kueri:
Keluaran:
db <> demo biola
sumber
Berikut adalah implementasi alternatif menggunakan XMLTABLE yang memungkinkan transmisi ke tipe data berbeda:
... atau jika string yang dipisahkan disimpan dalam satu atau beberapa baris tabel:
sumber
Saya ingin menambahkan metode lain. Yang ini menggunakan querys rekursif, sesuatu yang belum pernah saya lihat di jawaban lain. Ini didukung oleh Oracle sejak 11gR2.
Cukup fleksibel dengan karakter yang membelah. Cukup ubah dalam
INSTR
panggilan.sumber
Tanpa menggunakan connect by atau regexp :
sumber
Saya memiliki masalah yang sama, dan xmltable membantu saya:
PILIH id, potong (COLUMN_VALUE) teks DARI t, xmltable (('"' || REPLACE (teks, ',', '", "') || '"'))
sumber
Di Oracle 11g dan yang lebih baru, Anda dapat menggunakan sub-kueri rekursif dan fungsi string sederhana (yang mungkin lebih cepat daripada ekspresi reguler dan sub-kueri hierarki terkait):
Pengaturan Oracle :
Pertanyaan :
Keluaran :
db <> biola di sini
sumber
Saya telah menggunakan fungsi DBMS_UTILITY.comma_to _table sebenarnya yang bekerja dengan kode sebagai berikut
saya telah menggunakan nama tabel dan kolom saya sendiri
sumber
comma_to_table()
hanya berfungsi dengan token yang sesuai dengan konvensi penamaan objek database Oracle. Ini akan terlempar pada string seperti'123,456,789'
misalnya.