Gunakan modul unaccent untuk itu - yang sama sekali berbeda dari apa yang Anda tautkan.
unaccent adalah kamus pencarian teks yang menghilangkan aksen (tanda diakritik) dari leksem.
Instal sekali per database dengan:
CREATE EXTENSION unaccent;
Jika Anda mendapatkan kesalahan seperti:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
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 (jika LIKEtampaknya tidak diperlukan).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Indeks
Untuk menggunakan indeks untuk jenis kueri tersebut, buat indeks pada ekspresi . Namun , Postgres hanya menerima IMMUTABLEfungsi untuk indeks. Jika suatu fungsi dapat mengembalikan hasil yang berbeda untuk input yang sama, indeks dapat rusak secara diam-diam.
unaccent()hanya STABLEtidakIMMUTABLE
Sayangnya, unaccent()hanya STABLEtidak IMMUTABLE. Menurut utas tentang pgsql-bugs ini, ini karena tiga alasan:
- Itu tergantung pada perilaku kamus.
- Tidak ada koneksi terprogram ke kamus ini.
- Oleh karena itu, ini juga tergantung pada arus
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 sederhanaIMMUTABLE (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 IMMUTABLEfungsi 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.
CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text)
RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS
'$libdir/unaccent', 'unaccent_dict';
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS
$func$
SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1)
$func$;
Turun PARALLEL SAFEdari kedua fungsi untuk Postgres 9.5 atau yang lebih lama.
publicmenjadi skema tempat Anda memasang ekstensi ( publicadalah default).
Deklarasi tipe eksplisit ( regdictionary) melindungi dari serangan hipotetis dengan varian fungsi yang kelebihan beban oleh pengguna jahat.
Sebelumnya, saya menganjurkan fungsi pembungkus berdasarkan STABLEfungsi yang unaccent()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_tempke 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 IMMUTABLEfungsi di sekitar STABLE unaccent()fungsi yang disediakan oleh modul:
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary
$func$ LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT;
Akhirnya, indeks ekspresi membuat kueri cepat :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
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 unaccentmodul.
Sesuaikan kueri agar cocok dengan indeks (sehingga perencana kueri akan menggunakannya):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
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:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Anda akan menyukai pembaruan ini untuk unaccent di Postgres 9.6 :
Perluas file contrib/unaccentstandar unaccent.rulesuntuk menangani semua diakritik yang dikenal dengan Unicode, dan perluas pengikat dengan benar (Thomas Munro, Léonard Benedetti)
Penekanan saya yang berani. Sekarang kita mendapatkan:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Pencocokan pola
Untuk LIKEatau ILIKEdengan pola arbitrer, gabungkan ini dengan modul pg_trgmdi PostgreSQL 9.1 atau yang lebih baru. Buat trigram GIN (biasanya lebih disukai) atau indeks ekspresi GIST. Contoh untuk GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Dapat digunakan untuk pertanyaan seperti:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
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_trgmjuga 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 dengan ILIKE: