Saya mencoba menggunakan LISTAGG
fungsi di Oracle. Saya hanya ingin mendapatkan nilai yang berbeda untuk kolom itu. Apakah ada cara di mana saya hanya bisa mendapatkan nilai yang berbeda tanpa membuat fungsi atau prosedur?
col1 col2 Created_by 1 2 Smith 1 2 Yohanes 1 3 Ajay 1 4 Ram 1 5 Jack
Saya perlu memilih col1 dan LISTAGG
dari col2 (kolom 3 tidak dipertimbangkan). Ketika saya melakukan itu, saya mendapatkan sesuatu seperti ini sebagai hasil dari LISTAGG
: [2,2,3,4,5]
Saya perlu menghapus duplikat '2' di sini; Saya hanya membutuhkan nilai berbeda dari col2 terhadap col1.
sql
oracle
aggregate-functions
listagg
Priyanth
sumber
sumber
Jawaban:
19c dan lebih baru:
18c dan sebelumnya:
Jika Anda membutuhkan lebih banyak kolom, sesuatu seperti ini mungkin yang Anda cari:
sumber
listagg
merupakan satu-satunya fungsi agregat dalam kueri, ini harus dilakukan. Menggabungkannya dengan fungsi agregat lainnya, bagaimanapun, lebih rumit.Berikut cara mengatasi masalah Anda.
kembali
2,2.1,3,4
Dari oracle 19C dibangun lihat di sini
Dari 18C dan sebelumnya coba dalam lihat kelompok di sini
Jika tidak, gunakan ekspresi reguler
JAWABAN di bawah ini:
Catatan: Cara di atas akan berfungsi dalam banyak kasus - daftar harus diurutkan, Anda mungkin harus memangkas semua spasi di belakang dan di depan tergantung pada data Anda.
Jika Anda memiliki banyak item dalam grup> 20 atau ukuran string besar Anda mungkin mengalami batas ukuran string oracle 'hasil rangkaian string terlalu panjang'.
Dari oracle 12cR2 Anda dapat menekan kesalahan ini, lihat di sini . Atau berikan jumlah maksimal pada anggota di setiap grup. Ini hanya akan berfungsi jika tidak masalah untuk mencantumkan hanya anggota pertama. Jika Anda memiliki string variabel yang sangat panjang, ini mungkin tidak berfungsi. Anda harus bereksperimen.
Solusi lain (tidak sesederhana itu) untuk menghindari batas ukuran string oracle - ukuran string dibatasi hingga 4000. Terima kasih untuk posting ini di sini oleh user3465996
V1 - beberapa kasus uji - FYI
V2 -item yang terkandung dalam item mis. 2,21
v3 - regex terima kasih Igor! bekerja di semua kasus.
sumber
ORA-01489: result of string concatenation is too long
.a,b,b,b,b,c
akan menjadia,b,b,c
:-( (Oracle 11.2)regexp_replace(your_string, '([^,]+)(,\1)*(,|$)', '\1\3')
Anda bisa menggunakan
wm_concat
fungsi tidak berdokumen .fungsi ini mengembalikan kolom clob, jika Anda mau, Anda dapat menggunakan
dbms_lob.substr
untuk mengonversi clob ke varchar2.sumber
wm_concat(distinct x)
?wm_concat
. Lihat Mengapa tidak menggunakan fungsi WM_CONCAT di Oracle? .Saya mengatasi masalah ini dengan mengelompokkan nilai-nilai terlebih dahulu, kemudian melakukan agregasi lain dengan listagg. Sesuatu seperti ini:
hanya satu akses tabel penuh, relatif mudah diperluas ke kueri yang lebih kompleks
sumber
Jika tujuannya adalah untuk menerapkan transformasi ini ke beberapa kolom, saya telah memperluas solusi a_horse_with_no_name:
Ini adalah Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Produksi 64bit.
Saya tidak dapat menggunakan STRAGG karena tidak ada cara untuk MEMBEDAKAN dan MEMESAN.
Skala kinerja secara linier, yang bagus, karena saya menambahkan semua kolom yang menarik. Di atas membutuhkan waktu 3 detik untuk 77K baris. Hanya untuk satu rollup, 0,172 detik. Saya lakukan dengan ada cara untuk membedakan beberapa kolom dalam satu tabel dalam satu kali jalan.
sumber
Jika Anda menginginkan nilai yang berbeda di beberapa kolom, ingin mengontrol urutan, tidak ingin menggunakan fungsi tidak terdokumentasi yang mungkin hilang, dan tidak ingin lebih dari satu pemindaian tabel penuh, Anda mungkin menganggap konstruksi ini berguna:
sumber
Bagaimana dengan membuat fungsi khusus yang akan membuat bagian "berbeda":
Dan kemudian gunakan untuk melakukan agregasi:
sumber
Untuk mengatasi masalah panjang string Anda dapat menggunakan
XMLAGG
yang mirip denganlistagg
tetapi mengembalikan gumpalan.Anda kemudian dapat mengurai menggunakan
regexp_replace
dan mendapatkan nilai unik dan kemudian mengubahnya kembali menjadi string menggunakandbms_lob.substr()
. Jika Anda memiliki sejumlah besar nilai berbeda, Anda masih akan kehabisan ruang dengan cara ini tetapi untuk banyak kasus, kode di bawah ini seharusnya berfungsi.Anda juga dapat mengubah pembatas yang Anda gunakan. Dalam kasus saya, saya menginginkan '-' daripada ',' tetapi Anda harus dapat mengganti tanda hubung dalam kode saya dan menggunakan koma jika Anda menginginkannya.
sumber
Lebih lanjut menyempurnakan koreksi @ YoYo untuk pendekatan berbasis row_number () @ a_horse_with_no_name menggunakan DECODE vs CASE ( saya lihat di sini ). Saya melihat bahwa @Martin Vrbovsky juga memiliki jawaban pendekatan kasus ini.
sumber
Oracle 19c yang akan datang akan mendukung
DISTINCT
denganLISTAGG
.EDIT:
Oracle 19C LISTAGG DISTINCT
sumber
Adakah yang pernah berpikir untuk menggunakan klausa PARTITION BY? Saya berhasil dalam kueri ini untuk mendapatkan daftar layanan aplikasi dan aksesnya.
Saya harus memotong klausa where saya untuk NDA, tetapi Anda mengerti.
sumber
LISTAGG
. Tampaknya Anda hanya akan memiliki satuT.ACCESS_MODE
per baris karena Anda mengelompokkannya?Saya pikir ini bisa membantu - KASUS nilai kolom ke NULL jika itu duplikat - maka itu tidak ditambahkan ke string LISTAGG:
Hasil dalam:
sumber
listagg () mengabaikan nilai NULL, jadi pada langkah pertama Anda dapat menggunakan fungsi lag () untuk menganalisis apakah record sebelumnya memiliki nilai yang sama, jika ya maka NULL, atau 'nilai baru'.
Hasil
Perhatikan bahwa 2 kedua diganti dengan NULL. Sekarang Anda dapat membungkus SELECT dengan listagg () di sekitarnya.
Hasil
Anda juga dapat melakukan ini pada beberapa kolom.
Hasil
sumber
Anda dapat melakukannya melalui penggantian RegEx. Berikut ini contohnya:
Juga diposting di sini: Oracle - nilai Listagg unik
sumber
Gunakan fungsi listagg_clob yang dibuat seperti ini:
sumber
Saya menulis fungsi untuk menangani ini menggunakan ekspresi reguler. Parameter in adalah: 1) listagg memanggil dirinya sendiri 2) Pengulangan delimiter
Sekarang Anda tidak perlu mengulangi ekspresi reguler setiap kali melakukan ini, cukup ucapkan:
sumber
Jika Anda tidak memerlukan urutan nilai gabungan tertentu, dan pemisah dapat berupa koma, Anda dapat melakukan:
sumber
Saya membutuhkan versi yang BERBEDA dari ini dan yang ini berhasil.
sumber
Salah satu aspek yang mengganggu
LISTAGG
adalah jika total panjang string gabungan melebihi 4000 karakter (batas untukVARCHAR2
SQL), kesalahan di bawah ini muncul, yang sulit untuk dikelola dalam versi Oracle hingga 12.1Fitur baru yang ditambahkan di 12cR2 adalah
ON OVERFLOW
klausulLISTAGG
. Kueri yang menyertakan klausul ini akan terlihat seperti:Di atas akan membatasi keluaran menjadi 4000 karakter tetapi tidak akan membuang file
ORA-01489
kesalahan.Ini adalah beberapa opsi tambahan dari
ON OVERFLOW
klausa:ON OVERFLOW TRUNCATE 'Contd..'
: Ini akan ditampilkan'Contd..'
di akhir string (Default adalah...
)ON OVERFLOW TRUNCATE ''
: Ini akan menampilkan 4000 karakter tanpa string yang mengakhiri.ON OVERFLOW TRUNCATE WITH COUNT
: Ini akan menampilkan jumlah karakter di akhir setelah karakter yang diakhiri. Misalnya: - '...(5512)
'ON OVERFLOW ERROR
: Jika Anda mengharapkanLISTAGG
gagal denganORA-01489
kesalahan (Yang tetap default).sumber
Saya menerapkan fungsi tersimpan ini:
Maaf, tetapi dalam beberapa kasus (untuk set yang sangat besar), Oracle dapat mengembalikan kesalahan ini:
tapi saya pikir ini adalah titik awal yang baik;)
sumber
select col1, listaggr(col2,',') within group(Order by col2) from table group by col1
Artinya menggabungkan string (col2) ke dalam daftar dengan menjaga urutan n kemudian kemudian menangani duplikat sebagai grup dengan col1 yang berarti menggabungkan duplikat col1 dalam 1 grup. mungkin ini terlihat bersih dan sederhana sebagaimana mestinya dan jika Anda ingin col3 juga hanya Anda perlu menambahkan satu listagg () lagiselect col1, listaggr(col2,',') within group(Order by col2),listaggr(col3,',') within group(order by col3) from table group by col1
sumber
Menggunakan
SELECT DISTINCT ...
sebagai bagian dari Subquery sebelum memanggil LISTAGG mungkin adalah cara terbaik untuk kueri sederhana, seperti dicatat oleh @a_horse_with_no_nameNamun, dalam kueri yang lebih kompleks, hal ini mungkin tidak dapat dilakukan atau mudah dilakukan. Saya mendapatkan ini dalam skenario yang menggunakan pendekatan top-n menggunakan fungsi analitik.
Jadi saya menemukan
COLLECT
fungsi agregat. Ini didokumentasikan untuk memilikiUNIQUE
atauDISTINCT
pengubah tersedia. Hanya dalam 10g , itu diam-diam gagal (mengabaikan pengubah tanpa kesalahan). Namun, untuk mengatasinya, dari jawaban lain , saya sampai pada solusi ini:Pada dasarnya, dengan menggunakan
SET
, saya menghapus duplikat dalam koleksi saya.Anda masih perlu mendefinisikan
tab_typ
sebagai tipe koleksi dasar, dan dalam kasus aVARCHAR
, ini akan menjadi contoh:Juga sebagai koreksi atas jawaban dari @a_horse_with_no_name pada situasi multi kolom, di mana Anda mungkin ingin menggabungkan masih pada kolom ketiga (atau lebih):
Jika Anda membiarkan kondisi
rn = 1
sebagai tempat untuk kueri, Anda akan menggabungkan kolom lain dengan tidak benar.sumber
Sangat sederhana - gunakan dalam kueri Anda sub-kueri dengan pilihan yang berbeda:
sumber
Cara termudah untuk menangani beberapa listagg adalah dengan menggunakan 1 WITH (faktor subquery) per kolom yang berisi listagg kolom itu dari pilihan yang berbeda:
Pemberian yang mana:
sumber