Di Microsoft SQL Server, dimungkinkan untuk menentukan pemeriksaan "tidak peka aksen" (untuk database, tabel, atau kolom), yang berarti mungkin untuk kueri seperti
SELECT * FROM users WHERE name LIKE 'João'
untuk menemukan baris dengan Joao
nama.
Saya tahu bahwa mungkin saja untuk menghapus aksen dari string di PostgreSQL menggunakan fungsi kontrib unaccent_string, tetapi saya bertanya-tanya apakah PostgreSQL mendukung susunan "tidak sensitif aksen" ini sehingga cara di SELECT
atas akan berfungsi.
sql
postgresql
localization
indexing
pattern-matching
Daniel Serodio
sumber
sumber
Jawaban:
Gunakan modul unaccent untuk itu - yang sama sekali berbeda dari apa yang Anda tautkan.
Instal sekali per database dengan:
Jika Anda mendapatkan kesalahan seperti:
Instal paket contrib di server database Anda seperti yang diperintahkan dalam jawaban terkait ini:
Antara lain, ini menyediakan fungsi
unaccent()
yang dapat Anda gunakan dengan contoh Anda (jikaLIKE
tampaknya tidak diperlukan).Indeks
Untuk menggunakan indeks untuk jenis kueri tersebut, buat indeks pada ekspresi . Namun , Postgres hanya menerima
IMMUTABLE
fungsi untuk indeks. Jika suatu fungsi dapat mengembalikan hasil yang berbeda untuk input yang sama, indeks dapat rusak secara diam-diam.unaccent()
hanyaSTABLE
tidakIMMUTABLE
Sayangnya,
unaccent()
hanyaSTABLE
tidakIMMUTABLE
. Menurut utas tentang pgsql-bugs ini, ini karena tiga alasan:search_path
, yang dapat berubah dengan mudah.Beberapa tutorial di web menginstruksikan untuk mengubah volatilitas fungsi menjadi
IMMUTABLE
. Metode brute force ini bisa rusak dalam kondisi tertentu.Yang lain menyarankan fungsi pembungkus sederhana
IMMUTABLE
(seperti yang saya lakukan di masa lalu).Ada perdebatan yang sedang berlangsung apakah akan membuat varian dengan dua parameter
IMMUTABLE
yang mendeklarasikan kamus yang digunakan secara eksplisit. Baca di sini atau di sini .Alternatif lain adalah modul ini dengan fungsi IMMUTABLE
unaccent()
oleh Musicbrainz , yang disediakan di Github. Belum mengujinya sendiri. Saya pikir saya telah mendapatkan ide yang lebih baik :Terbaik untuk saat ini
Pendekatan ini lebih efisien karena solusi lain yang beredar, dan lebih aman .
Buat
IMMUTABLE
fungsi pembungkus SQL yang menjalankan formulir dua parameter dengan fungsi dan kamus yang memenuhi syarat skema berkabel.Karena menumpuk fungsi yang tidak dapat diubah akan menonaktifkan fungsi sebaris, mendasarkannya pada salinan fungsi-C, (palsu) juga dideklarasikan
IMMUTABLE
. Satu - satunya tujuan adalah digunakan dalam pembungkus fungsi SQL. Tidak dimaksudkan untuk digunakan sendiri.Kecanggihan diperlukan karena tidak ada cara untuk menghubungkan kamus secara keras dalam deklarasi fungsi C. (Akan perlu meretas kode C itu sendiri.) Fungsi SQL wrapper melakukan itu dan memungkinkan kedua fungsi sebaris dan indeks ekspresi.
Turun
PARALLEL SAFE
dari kedua fungsi untuk Postgres 9.5 atau yang lebih lama.public
menjadi skema tempat Anda memasang ekstensi (public
adalah default).Deklarasi tipe eksplisit (
regdictionary
) melindungi dari serangan hipotetis dengan varian fungsi yang kelebihan beban oleh pengguna jahat.Sebelumnya, saya menganjurkan fungsi pembungkus berdasarkan
STABLE
fungsi yangunaccent()
dikirimkan dengan modul unaccent. Fungsi yang dinonaktifkan itu sebaris . Versi ini dijalankan sepuluh kali lebih cepat daripada fungsi pembungkus sederhana yang saya miliki di sini sebelumnya.Dan itu sudah dua kali lebih cepat dari versi pertama yang ditambahkan
SET search_path = public, pg_temp
ke fungsi - sampai saya menemukan bahwa kamus juga bisa memenuhi syarat skema. Masih (Postgres 12) tidak terlalu terlihat dari dokumentasinya.Jika Anda tidak memiliki hak istimewa yang diperlukan untuk membuat fungsi C, Anda kembali ke implementasi terbaik kedua: Pembungkus
IMMUTABLE
fungsi di sekitarSTABLE
unaccent()
fungsi yang disediakan oleh modul:Akhirnya, indeks ekspresi membuat kueri cepat :
Ingatlah untuk membuat ulang indeks yang melibatkan fungsi ini setelah perubahan apa pun ke fungsi atau kamus, seperti pemutakhiran rilis utama di tempat yang tidak akan membuat ulang indeks. Rilis utama terbaru semuanya memiliki pembaruan untuk
unaccent
modul.Sesuaikan kueri agar cocok dengan indeks (sehingga perencana kueri akan menggunakannya):
Anda tidak membutuhkan fungsi dalam ekspresi yang benar. Di sana Anda juga dapat memberikan string tanpa aksen seperti
'Joao'
secara langsung.Fungsi yang lebih cepat tidak menerjemahkan ke kueri yang jauh lebih cepat menggunakan indeks ekspresi . Itu beroperasi pada nilai yang telah dihitung sebelumnya dan sudah sangat cepat. Tetapi pemeliharaan indeks dan kueri tidak menggunakan manfaat indeks.
Keamanan untuk program klien telah diperketat dengan Postgres 10.3 / 9.6.8 dll. Anda perlu fungsi yang memenuhi syarat skema dan nama kamus seperti yang ditunjukkan saat digunakan dalam indeks apa pun. Lihat:
Ligatur
Di Postgres 9.5 atau ligatur yang lebih lama seperti 'Œ' atau 'ß' harus diperluas secara manual (jika Anda membutuhkannya), karena
unaccent()
selalu mengganti satu huruf:Anda akan menyukai pembaruan ini untuk unaccent di Postgres 9.6 :
Penekanan saya yang berani. Sekarang kita mendapatkan:
Pencocokan pola
Untuk
LIKE
atauILIKE
dengan pola arbitrer, gabungkan ini dengan modulpg_trgm
di PostgreSQL 9.1 atau yang lebih baru. Buat trigram GIN (biasanya lebih disukai) atau indeks ekspresi GIST. Contoh untuk GIN:Dapat digunakan untuk pertanyaan seperti:
Indeks GIN dan GIST lebih mahal pemeliharaannya daripada btree biasa:
Ada solusi yang lebih sederhana untuk pola jangkar kiri saja. Lebih lanjut tentang pencocokan pola dan kinerja:
pg_trgm
juga menyediakan operator yang berguna untuk "kesamaan" (%
) dan "jarak" (<->
) .Indeks trigram juga mendukung ekspresi reguler sederhana dengan
~
et al. dan pola tidak peka huruf besar / kecil yang cocok denganILIKE
:sumber
unaccent(name)
?utf8_general_ci
merupakan jawaban untuk masalah seperti ini?Tidak, PostgreSQL tidak mendukung pemeriksaan dalam hal itu
PostgreSQL tidak mendukung pemeriksaan seperti itu (tidak sensitif aksen atau tidak) karena tidak ada perbandingan yang dapat menghasilkan nilai yang sama kecuali jika semuanya sama-biner. Ini karena secara internal akan memperkenalkan banyak kerumitan untuk hal-hal seperti indeks hash. Karena alasan ini, pemeriksaan dalam arti yang paling ketat hanya memengaruhi pengurutan , bukan kesetaraan.
Solusi
Kamus Pencarian-Teks Penuh yang Menghapus Aksen leksem.
Untuk FTS, Anda dapat menentukan kamus Anda sendiri menggunakan
unaccent
,Yang kemudian dapat Anda indeks dengan indeks fungsional,
Anda sekarang dapat menanyakannya dengan sangat sederhana
Lihat juga
Unaccent dengan sendirinya.
The
unaccent
modul juga dapat digunakan dengan sendirinya tanpa FTS-integrasi, untuk itu memeriksa jawaban Erwinsumber
Saya cukup yakin PostgreSQL bergantung pada sistem operasi yang mendasari untuk pemeriksaan. Ini tidak mendukung menciptakan collations baru , dan menyesuaikan collations . Saya tidak yakin berapa banyak pekerjaan yang mungkin untuk Anda. (Bisa jadi cukup banyak.)
sumber