TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
SQL Ready | Базы Данных

8 Oct, 09:12

Открыть в Telegram Поделиться Пожаловаться

Почему UNIQUE допускает несколько NULL в PostgreSQL!

Ограничение UNIQUE гарантирует уникальность значений, но для NULL в PostgreSQL действует отдельная семантика. По умолчанию два NULL считаются различными при проверке уникальности, поэтому ограничение не запрещает несколько строк с неопределённым значением:
CREATE TABLE users (
id BIGINT PRIMARY KEY,
email TEXT UNIQUE
);

Повторное определённое значение email нарушит ограничение уникальности.
INSERT INTO users (id, email)
VALUES (1, 'user@example.com');

INSERT INTO users (id, email)
VALUES (2, 'user@example.com');

При использовании NULL те же правила не применяются: несколько строк успешно проходят проверку ограничения.
INSERT INTO users (id, email)
VALUES
(3, NULL),
(4, NULL),
(5, NULL);

Особенно важно учитывать это поведение в составных ключах, где один из столбцов может быть неопределённым:
CREATE TABLE contacts (
id BIGINT PRIMARY KEY,
company_id BIGINT NOT NULL,
external_id TEXT,
UNIQUE (company_id, external_id)
);

Одинаковые определённые значения (company_id, external_id) конфликтуют, но несколько комбинаций (10, NULL) по умолчанию допустимы:
INSERT INTO contacts (id, company_id, external_id)
VALUES
(1, 10, NULL),
(2, 10, NULL);

Начиная с PostgreSQL 15 это поведение можно изменить через NULLS NOT DISTINCT. В таком ограничении NULL считаются неразличимыми при проверке уникальности:
CREATE TABLE contacts_strict (
id BIGINT PRIMARY KEY,
company_id BIGINT NOT NULL,
external_id TEXT,
UNIQUE NULLS NOT DISTINCT (company_id, external_id)
);

Теперь сохранить две строки с одной комбинацией (10, NULL) нельзя: вторая вставка завершится нарушением уникальности.
INSERT INTO contacts_strict (id, company_id, external_id)
VALUES (1, 10, NULL);

INSERT INTO contacts_strict (id, company_id, external_id)
VALUES (2, 10, NULL);

Та же семантика поддерживается уникальными индексами, поэтому правило можно выразить непосредственно на уровне индекса.
CREATE UNIQUE INDEX uq_contacts_company_external
ON contacts (company_id, external_id)
NULLS NOT DISTINCT;

NULLS NOT DISTINCT не эквивалентен NOT NULL. NOT NULL полностью запрещает отсутствие значения, тогда как NULLS NOT DISTINCT разрешает NULL, но включает его в контроль уникальности.
CREATE TABLE identifiers (
id BIGINT PRIMARY KEY,
external_id TEXT,
UNIQUE NULLS NOT DISTINCT (external_id)
);

В такой таблице может существовать одна строка с external_id IS NULL, но вторая аналогичная строка уже нарушит ограничение.

🔥 UNIQUE в PostgreSQL по умолчанию допускает несколько NULL. Если отсутствие значения также должно быть уникальным состоянием, начиная с PostgreSQL 15 это можно явно зафиксировать через NULLS NOT DISTINCT.

➡️ SQL Ready | #практика

1.1k 0 19 1 24
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot