Используйте для этого модуль unaccent , который полностью отличается от того, на что вы ссылаетесь.
unaccent - это словарь текстового поиска, удаляющий акценты (диакритические знаки) из лексем.
Установите один раз для каждой базы данных с помощью:
CREATE EXTENSION unaccent;
Если вы получите сообщение об ошибке:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Установите пакет contrib на свой сервер базы данных, как указано в соответствующем ответе:
Среди прочего, он предоставляет функцию, которую unaccent()вы можете использовать в своем примере (там, где это LIKEкажется ненужным).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Индекс
Чтобы использовать индекс для такого типа запроса, создайте индекс для выражения . Однако Postgres принимает IMMUTABLEфункции только для индексов. Если функция может вернуть другой результат для одного и того же ввода, индекс может молча прерваться.
unaccent()только STABLEнеIMMUTABLE
К сожалению, unaccent()только STABLEнет IMMUTABLE. Согласно этой теме на pgsql-bugs , это происходит по трем причинам:
- Это зависит от поведения словаря.
- К этому словарю нет проводного подключения.
- Следовательно, это также зависит от тока
search_path, который может легко измениться.
Некоторые обучающие программы в Интернете инструктируют просто изменить волатильность функции на IMMUTABLE. Этот метод грубой силы может сломаться при определенных условиях.
Другие предлагают простую IMMUTABLEфункцию-оболочку (как я сам делал в прошлом).
Продолжаются дискуссии о том, следует ли делать вариант с двумя параметрами, IMMUTABLE который явно объявляет используемый словарь. Читайте здесь или здесь .
Другая альтернатива была бы этот модуль с непреложной unaccent()функцией по MusicBrainz , представленной на Github. Сам не тестировал. Думаю, я придумал лучшую идею :
Лучшее на данный момент
Этот подход более эффективен, чем другие решения, и безопаснее .
Создайте функцию- IMMUTABLEоболочку SQL, выполняющую двухпараметрическую форму с зашитой функцией и словарем, квалифицированной схемой.
Поскольку вложение неизменяемой функции отключит встраивание функции, основывайте его на копии объявленной C-функции (поддельной) IMMUTABLE. Его единственное назначение - использовать в оболочке функции SQL. Не предназначен для использования отдельно.
Изощренность необходима, поскольку нет возможности жестко привязать словарь к объявлению функции C. (Потребуется взломать сам код C.) Функция-оболочка SQL делает это и позволяет как встраивание функций, так и индексы выражений.
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$;
Откажитесь PARALLEL SAFEот обеих функций для Postgres 9.5 или старше.
publicСхема, в которую вы установили расширение ( publicпо умолчанию).
Явное объявление типа ( regdictionary) защищает от гипотетических атак злонамеренных пользователей с перегруженными вариантами функции.
Ранее я выступал за функцию-оболочку, основанную на STABLEфункции, unaccent()поставляемой с модулем unaccent. Эта отключенная функция встраивается . Эта версия выполняется в десять раз быстрее, чем простая функция-оболочка, которую я использовал здесь ранее.
И это было уже в два раза быстрее, чем в первой версии, добавленной SET search_path = public, pg_tempк функции - пока я не обнаружил, что словарь также может быть квалифицирован по схеме. Тем не менее (Postgres 12) не слишком очевиден из документации.
Если у вас нет необходимых привилегий для создания функций C, вы вернетесь ко второй лучшей реализации: IMMUTABLEобертка функции вокруг STABLE unaccent()функции, предоставляемой модулем:
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;
Наконец, индекс выражения для быстрого выполнения запросов :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Не забудьте воссоздать индексы, включающие эту функцию, после любого изменения функции или словаря, например, при обновлении основного выпуска на месте, при котором индексы воссоздавать не будут. Все последние основные выпуски содержали обновления unaccentмодуля.
Адаптируйте запросы к индексу (чтобы планировщик запросов использовал его):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Вам не нужна функция в правильном выражении. Там вы также можете указать строки без ударения, например, 'Joao'напрямую.
Более быстрая функция не преобразуется в гораздо более быстрые запросы с использованием индекса выражения . Это работает с предварительно вычисленными значениями и уже работает очень быстро. Но обслуживание индекса и запросы, не использующие преимущества индекса.
Безопасность клиентских программ была усилена с помощью Postgres 10.3 / 9.6.8 и т. Д. Вам необходимо указать функцию и имя словаря с указанием схемы, как показано при использовании в любых индексах. Видеть:
Лигатуры
В Postgres 9.5 или более ранних лигатуры, такие как 'Œ' или 'ß', должны быть расширены вручную (если вам это нужно), поскольку unaccent()всегда заменяет одну букву:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Вам понравится это обновление до Unaccent в Postgres 9.6 :
contrib/unaccentСтандартный unaccent.rulesфайл Extend для обработки всех диакритических знаков, известных в Unicode, и правильного расширения лигатур (Томас Манро, Леонард Бенедетти)
Смелый акцент мой. Теперь получаем:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Сопоставление с образцом
Для произвольных шаблонов LIKEили ILIKEс ними объедините это с модулем pg_trgmв PostgreSQL 9.1 или новее. Создайте триграмму GIN (обычно предпочтительнее) или индекс выражения GIST. Пример для GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Может использоваться для таких запросов:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
Индексы GIN и GIST обходятся дороже, чем обычные btree:
Есть более простые решения только для шаблонов с левым якорем. Подробнее о сопоставлении с образцом и производительности:
pg_trgmтакже предоставляет полезные операторы для «подобия» ( %) и «расстояния» ( <->). .
Индексы триграммы также поддерживают простые регулярные выражения с помощью ~et al. и чувствителен к регистру сопоставление с образцом с ILIKE: