Lessons › SQL › Deep Dive: Data Cleaning
SQL lesson
Removing duplicates with ROW_NUMBER() and DELETE
ROW_NUMBER() assigns a unique sequence number to each row within a group of identical records, so you can safely target every copy after the first for deletion.
Try this lesson free →Example
Removing Duplicate Retail Orders with ROW_NUMBER()
WITH ranked AS (
SELECT ctid,
ROW_NUMBER() OVER (PARTITION BY order_id, customer_id, order_date, revenue ORDER BY ctid) AS rn
FROM orders
)
DELETE FROM orders
WHERE ctid IN (SELECT ctid FROM ranked WHERE rn > 1)| kept_orders |
|---|
| O2001 |
| O2002 |
| O2003 |
Step by step
- WITH lets you name a sub-query so the main query can reference it.
WITH ranked AS ( SELECT ctid, ROW_NUMBER() OVER (PARTITION BY order_id, customer_id, order_date, revenue ORDER BY ctid) AS rn FROM orders ) - DELETE FROM removes rows from a table.
WITH ranked AS ( SELECT ctid, ROW_NUMBER() OVER (PARTITION BY order_id, customer_id, order_date, revenue ORDER BY ctid) AS rn FROM orders ) DELETE FROM orders - WHERE keeps only the rows that match your condition.
WITH ranked AS ( SELECT ctid, ROW_NUMBER() OVER (PARTITION BY order_id, customer_id, order_date, revenue ORDER BY ctid) AS rn FROM orders ) DELETE FROM orders WHERE ctid IN (SELECT ctid FROM ranked WHERE rn > 1);
Practice
1. On customers, remove duplicate rows that share the same phone. Keep the row with the lowest customer_id in each duplicate group. Use a CTE with ROW_NUMBER() + DELETE.
WITH ranked AS (SELECT customer_id, ROW_NUMBER() OVER (PARTITION BY phone ORDER BY customer_id) AS rn FROM customers) DELETE FROM customers WHERE customer_id IN (SELECT customer_id FROM ranked WHERE rn > 1)2. On products, remove duplicate rows that share the same category. Keep the row with the lowest product_id in each duplicate group. Use a CTE with ROW_NUMBER() + DELETE.
WITH ranked AS (SELECT product_id, ROW_NUMBER() OVER (PARTITION BY category ORDER BY product_id) AS rn FROM products) DELETE FROM products WHERE product_id IN (SELECT product_id FROM ranked WHERE rn > 1)3. On orders, remove duplicate rows that share the same category. Keep the row with the lowest order_id in each duplicate group. Use a CTE with ROW_NUMBER() + DELETE.
WITH ranked AS (SELECT order_id, ROW_NUMBER() OVER (PARTITION BY category ORDER BY order_id) AS rn FROM orders) DELETE FROM orders WHERE order_id IN (SELECT order_id FROM ranked WHERE rn > 1)4. On inventory, remove duplicate rows that share the same warehouse. Keep the row with the lowest product_id in each duplicate group. Use a CTE with ROW_NUMBER() + DELETE.
WITH ranked AS (SELECT product_id, ROW_NUMBER() OVER (PARTITION BY warehouse ORDER BY product_id) AS rn FROM inventory) DELETE FROM inventory WHERE product_id IN (SELECT product_id FROM ranked WHERE rn > 1)5. On reviews, remove duplicate rows that share the same product_id. Keep the row with the lowest review_id in each duplicate group. Use a CTE with ROW_NUMBER() + DELETE.
WITH ranked AS (SELECT review_id, ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY review_id) AS rn FROM reviews) DELETE FROM reviews WHERE review_id IN (SELECT review_id FROM ranked WHERE rn > 1)Learn it by doing. This lesson is a short hands-on level on Bampaa: see it work, then build and write it yourself, with instant feedback.
Try this lesson free →