← Back to libraryQuestion 209 of 273
🗄️SQLIntermediate

Finding Duplicates

📌 Definition:

Finding duplicates means identifying rows that repeat a value (or combination of values) that should be unique — duplicate emails, repeated orders, doubled records from a bad import. The standard technique is GROUP BY the columns that should be unique and keep groups with COUNT(*) > 1.

📖 Detailed Explanation:

Duplicate data is one of the most common defects testers hunt, arising from missing unique constraints, retried operations, or faulty imports. The canonical detection query groups by the column(s) expected to be unique and filters HAVING COUNT(*) > 1, returning each duplicated value with its occurrence count. To see the actual duplicate rows (not just the values), you either join that result back to the table or use a window function (ROW_NUMBER partitioned by the key) and select rows where the row number is greater than 1 — which also underpins de-duplication, since those are the rows you'd delete to keep one copy. Composite duplicates (same first_name + last_name + dob) group by all the relevant columns. A subtlety: values differing only by case or trailing whitespace ('Test@x.com' vs 'test@x.com ') may be logical duplicates that an exact GROUP BY misses, so normalization (LOWER, TRIM) is often needed for real-world duplicate detection.

🔑 Key Points:
  • Core pattern: GROUP BY the unique column(s) HAVING COUNT(*) > 1
  • Returns the duplicated values and how many times each occurs
  • To see/delete the actual extra rows, use ROW_NUMBER() partitioned by the key
  • Composite duplicates group by all relevant columns together
  • Normalize (LOWER/TRIM) to catch case/whitespace 'logical' duplicates
🌍 Real-World Example:

After a signup bug report, a tester checks for duplicate accounts with SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1 — instantly listing every email registered more than once, confirming the missing unique constraint.

📎 Code Example:
-- Which emails are duplicated, and how many times?
SELECT email, COUNT(*) AS occurrences
FROM users
GROUP BY email
HAVING COUNT(*) > 1
ORDER BY occurrences DESC;

-- Catch case/whitespace duplicates too
SELECT LOWER(TRIM(email)) AS normalized_email, COUNT(*) AS occurrences
FROM users
GROUP BY LOWER(TRIM(email))
HAVING COUNT(*) > 1;

-- See the actual extra rows (row number > 1 = duplicates to remove)
SELECT * FROM (
  SELECT id, email,
         ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) AS rn
  FROM users
) t
WHERE rn > 1;
🎯 Scenario-Based Interview Question:

Scenario: A bug report says some customers receive two confirmation emails. A tester runs SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1 and gets zero rows, concluding there are no duplicate accounts — yet the duplicates clearly exist. What could the exact-match query be missing, and how do you find the real duplicates?