Знайти дублікати - групування за колонками, що мали б бути унікальними:
SELECT email, COUNT(*) AS copies, MIN(id) AS keep_id
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
Побачити всі рядки-дублікати з порядковим номером - віконна функція:
SELECT *
FROM (
SELECT u.*,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at, id) AS rn
FROM users u
) t
WHERE rn > 1; -- усе, крім першого запису кожного email
ORDER BY визначає, який запис залишити: найстаріший, найновіший, найповніший.
Видалити дублікати:
DELETE u
FROM users u
JOIN (
SELECT id
FROM (
SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at, id) AS rn
FROM users
) ranked
WHERE rn > 1
) dup ON dup.id = u.id;
Подвійне вкладення обходить обмеження MySQL на читання з тієї ж таблиці, з якої видаляють.
Перш ніж видаляти:
- Злити пов'язані дані: замовлення, коментарі, підписки дублікатів перепризначити на запис, що залишається. Інакше вони або зникнуть каскадом, або залишаться «сиротами».
- Нормалізувати значення:
Olia@Example.comіolia@example.com- теж дублікати, якщо порівнювати з урахуванням регістру й пробілів. - Зробити бекап або перенести дублікати в окрему таблицю, а не видаляти одразу.
Головне - не допустити повторення: додати унікальний індекс після очищення (ALTER TABLE users ADD UNIQUE (email)). Без нього дублікати з'являться знову - через гонку двох одночасних реєстрацій чи імпорт.