citext — регистронезависимый строковый тип данных#
Примечание
Эта страница переведена при помощи нейросети GigaChat.
Модуль citext предоставляет тип данных для строк без учета регистра, citext. По сути, он внутренне вызывает lower при сравнении значений. В остальном он ведет себя почти точно так же, как text.
Совет
Рассмотрите возможность использования недетерминированных параметров сортировки вместо этого модуля. Они могут использоваться для нечувствительных к регистру сравнений, сравнений без учета акцентов и других комбинаций, а также правильно обрабатывают больше специальных случаев Unicode.
Этот модуль считается «надежным», то есть его может установить не суперпользователь, имеющий привилегию CREATE на текущей базе данных.
Обоснование#
Стандартный подход к выполнению нечувствительных к регистру совпадений в PostgreSQL заключался в использовании функции lower при сравнении значений, например:
SELECT * FROM tab WHERE lower(col) = LOWER(?);
Это работает достаточно хорошо, но имеет ряд недостатков:
Операторы SQL станиовятся многословными, при этом всегда нужно помнить о необходимости использовать
lowerкак для столбца, так и для значения запроса.Индекс не будет использоваться, если не создан функциональный индекс с использованием
lower.Если столбец объявлен как
UNIQUEилиPRIMARY KEY, автоматически созданный индекс будет чувствительным к регистру. Таким образом, он бесполезен для поиска без учета регистра и не обеспечит уникальность без учета регистра.
Тип данных citext позволяет исключить вызовы lower в SQL-запросах и позволяет сделать первичный ключ нечувствительным к регистру. citext учитывает локаль, так же как и text, что означает, что сопоставление символов верхнего и нижнего регистра зависит от настроек LC_CTYPE базы данных. Опять же, это поведение идентично использованию lower в запросах. Но поскольку это делается прозрачно типом данных, то не нужно помнить о том, чтобы делать что-то особенное в запросах.
Как его использовать#
Простой пример использования:
CREATE TABLE users (
nick CITEXT PRIMARY KEY,
pass TEXT NOT NULL
);
INSERT INTO users VALUES ( 'larry', sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Tom', sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Damian', sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'NEAL', sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Bjørn', sha256(random()::text::bytea) );
SELECT * FROM users WHERE nick = 'Larry';
Оператор SELECT вернет одну кортежную пару, даже если столбец nick был установлен на larry и запрос был для Larry.
Поведение при сравнении строк#
citext выполняет сравнение путем преобразования каждой строки в нижний регистр (как будто вызывается lower) и затем сравнивает результаты обычным образом. Таким образом, например, две строки считаются равными, если lower даст одинаковые результаты для них.
Чтобы максимально точно имитировать нечувствительное к регистру сопоставление, существуют версии с учетом регистра для ряда операторов и функций обработки строк. Так, например, операторы регулярных выражений ~ и ~* демонстрируют одинаковое поведение при применении к citext: они оба соответствуют без учета регистра. То же самое относится к !~ и !~*, а также к операторам LIKE ~~ и ~~*, и !~~ и !~~*. Если нужно, чтобы эти операторы учитывали регистр, можно привести их аргументы оператора к text.
Аналогично, все следующие функции выполняют сопоставление без учета регистра, если их аргументы являются citext:
regexp_match();regexp_matches();regexp_replace();regexp_split_to_array();regexp_split_to_table();replace();split_part();strpos();translate().
Для функций регулярного выражения, если требуется выполнить сопоставление с учетом регистра, можно указать флаг «c» для принудительного сопоставления с учетом регистра. В противном случае необходимо преобразовать в text перед использованием одной из этих функций, если необходимо поведение с учетом регистра.
Ограничения#
Поведение
citextпри преобразовании регистра зависит от настройкиLC_CTYPEбазы данных. Таким образом, способ сравнения значений определяется при создании базы данных. Это не является действительно нечувствительным к регистру в терминах, определенных стандартом Unicode. По сути, это означает, что до тех пор, пока присутствует удовлетворенность сортировкой, должно подходить сравнениеcitext. Но если есть данные на разных языках, хранящиеся в базе данных, пользователи одного языка могут обнаружить, что результаты их запросов отличаются от ожидаемых, если сортировка предназначена для другого языка.Начиная с PostgreSQL 9.1, можно прикрепить спецификацию
COLLATEк столбцамcitextили значениям данных. В настоящее время операторыcitextбудут учитывать нестандартную спецификациюCOLLATEпри сравнении строк со сложенным регистром, но начальное сворачивание в нижний регистр всегда выполняется в соответствии с настройкойLC_CTYPEбазы данных (то есть так, как будто было даноCOLLATE "default"). Это может быть изменено в будущем выпуске таким образом, чтобы оба шага следовали спецификации вводаCOLLATE.citextменее эффективен, чемtext, потому что функции операторов и функции сравнения B-дерева должны копировать данные и преобразовывать их в нижний регистр для сравнений. Кроме того, толькоtextможет поддерживать дедупликацию B-дерева. Однакоcitextнемного эффективнее, чем использованиеlowerдля получения нечувствительного к регистру соответствия.citextмало помогает, если нужно сравнивать данные с учетом регистра в некоторых контекстах и без учета регистра в других контекстах. Стандартный ответ заключается в использовании типаtextи ручном использовании функцииlowerпри необходимости сравнения без учета регистра. Это работает нормально, если сравнение без учета регистра требуется лишь изредка. Если чаще всего требуется поведение, нечувствительное к регистру, и редко чувствительное к регистру, рассмотрите возможность хранения данных какcitextи явного приведения столбца к типуtextпри желании сравнить его с учетом регистра. В любом случае понадобятся два индекса, если нужно, чтобы оба типа поиска выполнялись быстро.Схема, содержащая операторы
citext, должна находиться в текущейsearch_path(обычноpublic). Если это не так, вместо этого будут вызваны обычные регистрозависимые операторыtext.Подход с преобразованием строк в нижний регистр для сравнения не обрабатывает некоторые специальные случаи Unicode правильно, например, когда одна прописная буква имеет два эквивалентных строчных символа. Поэтому в Unicode различаются понятия преобразование регистра (case mapping) и выравнивание регистра (case folding). Используйте недетерминированные сопоставления вместо
citextдля правильной обработки.