PostgreSQL: уникальный email без учёта регистра
Обычное UNIQUE для text различает регистр. Создайте функциональный unique index по lower(email), чтобы база запрещала Anna@example.com и anna@example.com как один адрес. ??????? ????????? ?????? ?? ????????? ??????? ? ??????? ???? ?????????? ?? ????? ??????.
Рабочий пример
CREATE TEMP TABLE users(email text);
CREATE UNIQUE INDEX users_email_lower_uq ON users (lower(email));
INSERT INTO users VALUES ('Anna@example.com');
INSERT INTO users VALUES ('boris@example.com');
SELECT lower(email) AS normalized FROM users ORDER BY normalized;Индекс нужен для фактического инварианта уникальности, а не только для ускорения SELECT. Для Unicode правила регистра зависят от collation и версии, поэтому проверьте нужную локаль.
Частый вопрос
Подойдёт ли тип citext?
citext упрощает case-insensitive сравнения, но зависит от расширения и collation. Функциональный индекс явно задаёт правило и подходит, если оно ограничено конкретной колонкой.