Как проверить уникальность в SQL

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

Три способа проверить уникальность

  1. COUNT vs COUNT DISTINCT — быстро узнать, есть ли дубли
  2. GROUP BY + HAVING — найти конкретные дубли
  3. UNIQUE constraint — запретить дубли на уровне БД

1. Есть ли вообще дубликаты

SELECT
    COUNT(*) AS total,
    COUNT(DISTINCT email) AS unique_emails,
    COUNT(*) - COUNT(DISTINCT email) AS duplicates
FROM users;

Если duplicates = 0 — уникальность соблюдается.

2. Найти дубли по одной колонке

SELECT email, COUNT(*) AS cnt
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

3. Найти дубли по комбинации

SELECT first_name, last_name, birth_date, COUNT(*)
FROM users
GROUP BY first_name, last_name, birth_date
HAVING COUNT(*) > 1;

4. Уникальность без учёта регистра

SELECT LOWER(email), COUNT(*) AS cnt
FROM users
GROUP BY LOWER(email)
HAVING COUNT(*) > 1;

5. Уникальность без пробелов

SELECT TRIM(name), COUNT(*) AS cnt
FROM users
GROUP BY TRIM(name)
HAVING COUNT(*) > 1;

6. Уникальность с учётом NULL

-- NULL группируется вместе (не все хотят)
SELECT email, COUNT(*)
FROM users
WHERE email IS NOT NULL
GROUP BY email
HAVING COUNT(*) > 1;

7. UNIQUE constraint (запрет дублей)

-- при создании таблицы
CREATE TABLE users (
    id INT PRIMARY KEY,
    email VARCHAR(255) UNIQUE
);

-- добавить к существующей
ALTER TABLE users
ADD CONSTRAINT uq_users_email UNIQUE (email);

-- UNIQUE на несколько колонок
ALTER TABLE order_items
ADD CONSTRAINT uq_order_product UNIQUE (order_id, product_id);

После UNIQUE constraint INSERT дубля даст ошибку.

8. Посмотреть существующие unique constraints

Postgres

SELECT conname, contype, pg_get_constraintdef(oid)
FROM pg_constraint
WHERE contype = 'u' AND conrelid = 'users'::regclass;

MySQL

SHOW INDEX FROM users WHERE Non_unique = 0;

9. Проверка перед INSERT

-- INSERT только если такой email не существует
INSERT INTO users (email, name)
SELECT 'alice@example.com', 'Alice'
WHERE NOT EXISTS (
    SELECT 1 FROM users WHERE email = 'alice@example.com'
);

Или ON CONFLICT (Postgres):

INSERT INTO users (email, name)
VALUES ('alice@example.com', 'Alice')
ON CONFLICT (email) DO NOTHING;

Частые ошибки

NULL при сравнении

COUNT(*) vs COUNT(col) — разница. COUNT(col) игнорирует NULL.

UNIQUE с NULL

В UNIQUE несколько NULL разрешены (так в большинстве СУБД). Если это проблема — используйте NOT NULL UNIQUE.

Регистр

Alicealice в большинстве collations. Для case-insensitive используйте LOWER() или CITEXT в Postgres.

Связанные темы

FAQ

Как проверить uniqueness в огромной таблице?

COUNT DISTINCT на индексированной колонке — относительно быстро. Approximate count (uniq в ClickHouse) — ещё быстрее.

UNIQUE и PRIMARY KEY — это одно?

PK = UNIQUE + NOT NULL + один на таблицу. UNIQUE может быть несколько, с NULL.

Чем проверять уникальность в ETL?

Встраивайте в pipeline COUNT vs COUNT(DISTINCT) как sanity check. dbt tests делают это автоматически.


Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.