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 LIKE
tampaknya 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 IMMUTABLE
fungsi untuk indeks. Jika suatu fungsi dapat mengembalikan hasil yang berbeda untuk input yang sama, indeks dapat rusak secara diam-diam.
unaccent()
hanya STABLE
tidakIMMUTABLE
Sayangnya, unaccent()
hanya STABLE
tidak 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 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.
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 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 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_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 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 unaccent
modul.
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/unaccent
standar unaccent.rules
untuk 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 LIKE
atau ILIKE
dengan pola arbitrer, gabungkan ini dengan modul pg_trgm
di 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_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 dengan ILIKE
: