Найти строки, дублирующиеся по (email, phone), и оставить только самую раннюю
Таблица people(id, email, phone, created_at) содержит дубли людей с одинаковыми (email, phone). Верните ровно одну строку на (email, phone) — самую раннюю по created_at — чтобы дубли схлопнулись до первого появления.
-- одна строка на (email, phone): самая ранняя по created_at
Напишите запрос.
Нумеруют строки внутри каждой пары (email, phone) по возрасту и берут первую — ROW_NUMBER() OVER (PARTITION BY email, phone ORDER BY created_at) AS rn в подзапросе, затем фильтр rn = 1. Обычный GROUP BY схлопнул бы группу, но не вернул бы всю раннюю строку целиком.
- ✗Ждать, что DISTINCT выберет раннюю строку, а не точные дубли
- ✗Считать, что MIN(created_at) тянет прочие столбцы из той же строки
- ✗Полагаться на физический порядок строк вместо явного ORDER BY
- →Как разрешить ничьи, когда две строки делят один created_at?
- →Как изменится запрос, если дубли нужно удалить на месте?
Number the rows within each (email, phone) pair oldest-first, then keep rank one. This returns the whole original row, not just the grouping key.
WITH ranked AS (
SELECT people.*,
ROW_NUMBER() OVER (PARTITION BY email, phone
ORDER BY created_at) AS rn
FROM people
)
SELECT id, email, phone, created_at
FROM ranked
WHERE rn = 1;
Why the alternatives fail: DISTINCT only removes rows identical across every selected column, so differing id/created_at values keep the duplicates. GROUP BY email, phone with MIN(created_at) collapses each pair, but a bare id beside it is not guaranteed to come from that earliest row. The window function keeps the full row and picks the first deterministically.