Identify and Delete Duplicate records in SQL Server
How to get and delete duplicate rows / records in SQL Server
Search for a command to run...
How to get and delete duplicate rows / records in SQL Server
No comments yet. Be the first to comment.
I recently completed a series of interviews for engineering roles, and one key theme stood out: SQL and PostgreSQL aren’t just about writing queries — they’re about knowing how data systems work under pressure. On my main blog, I broke down: The exa...
In today's data-driven world, speed and performance are crucial for staying ahead. SQL Server's In-Memory OLTP (Hekaton) is a great feature that helps businesses meet the needs of high-performance, low-latency applications. Whether you're working on ...
This post demonstrates the integration of external Rest APIs with Azure SQL Database and Azure API Management Service. By utilizing the system-stored procedure sp_invoke_external_rest_endpoint, you can make REST calls to endpoints such as Azure Funct...
System-Versioned Temporal Tables, also known as History Tables are a built-in feature that keeps track of data changes in SQL Server. Unlike regular tables that only show the current data state, these tables help in seamlessly capturing and preservin...
This post is to understand and demonstrate TRY CATCH in SQL Server, we will also see, how to trigger and handle custom exceptions with example.
As a developer, you already know that any database table should not contain duplicate rows. But sometimes, we overlook these principles due to certain requirements or when we are importing data from different data-source like csv, databases, json etc. These scenarios lead to duplicate rows or records of data in a table.
There are many ways to get or identify duplicate rows and delete duplicate rows, we have to consider if the given table has a unique index or not. I do it below
Lets create a table and queries for reference,
create table customers(
id int identity(1,1) primary key,
first_name varchar(40) not null,
last_name varchar(40),
email varchar(100) not null,
active bit not null default(1)
);
insert into customers(first_name, last_name, email) values
('Ken', 'Sanchez', 'ken@Sanchez.com'),
('Terri', 'Duffy', 'terri@duffy.com'),
('Roberto', 'Tamburello', 'rob@tam.com'),
('Rob', 'Walters', 'rob@walters.com'),
('Gail', 'Erickson', 'gail@eric.com'),
('Jossef', 'Erickson', 'jossef@eric.com'),
('Dylan', 'Miller', 'dylan@miller.com'),
('Diane', 'Margheim', 'diane@margheim.com'),
('Ken', 'Sanchez', 'ken@Sanchez.com'),
('Ken', 'Sanchez', 'ken@Sanchez.com');
select * from customers -- get's all rows from the customers table
select
first_name, last_name, email, count(*) as duplicate_count
from customers
group by first_name, last_name, email; -- return table with duplicate_count
As our customers table is ready, let's identify duplicate rows in the customers table, as we know it has duplicate rows and their count.
select
a.*
from customers a
join
(
select id, row_number() over(partition by first_name, last_name, email order by id) as ranking from customers
) b
on a.id = b.id
where b.ranking > 1;
The above query will return the below row set id first_name last_name email active 9 Ken Sanchez ken@Sanchez.com 1 10 Ken Sanchez ken@Sanchez.com 1
These rows are duplicate rows, baring the first occurrence of the same data in the table.
delete
a
from customers a
join
(
select id, row_number() over (partition by first_name, last_name, email order by id) as ranking from customers
) b
on a.id = b.id
where b.ranking > 1
Here in the above query, with help of SQL Windows Function, we got the id and row_number (here referred to as ranking) from the customers table partitioned by the columns we want to group firstly, then we performed inner join with the customers table outside on condition of both the id but in where clause, using b.ranking > 1 we only got those records whose ranking is greater than one. Since the ranking will increase as many times as the records are duplicated in the table. In our case, it will keep the first record but will delete two duplicate records or rows.
When the table doesn't have any unique index or primary key, then we can do it using CTE. let's create a table and insert data and demonstrate it.
create table customers(
first_name varchar(40) not null,
last_name varchar(40),
email varchar(100),
active bit not null default(1)
);
insert into customers(first_name, last_name, email) values
('Ken', 'Sanchez', 'ken@Sanchez.com'),
('Terri', 'Duffy', 'terri@duffy.com'),
('Roberto', 'Tamburello', 'rob@tam.com'),
('Rob', 'Walters', 'rob@walters.com'),
('Gail', 'Erickson', 'gail@eric.com'),
('Jossef', 'Erickson', 'jossef@eric.com'),
('Dylan', 'Miller', 'dylan@miller.com'),
('Diane', 'Margheim', 'diane@margheim.com'),
('Ken', 'Sanchez', 'ken@Sanchez.com'),
('Ken', 'Sanchez', 'ken@Sanchez.com');
select * from customers; -- get all customers
select
*, row_number() over(partition by first_name, last_name, email order by first_name) as row_num
from customers;
In the above query, we used the row_number() function on customers table by partitioning the required column and as we can see, the row_num column has a value of 1 except for the duplicate rows, whose row_num values are greater than 1. So, the query below will return us only duplicate rows
with customers_cte as (
select
*, row_number() over(partition by first_name, last_name, email order by first_name) as row_num
from customers
)
select * from customers_cte where row_num > 1; -- runts duplicate rows only
To delete the duplicate rows, we will use the CTE and windows function similar to the above, we did for identifying the duplicate rows.
with customers_cte as (
select
*, row_number() over(partition by first_name, last_name, email order by first_name) as row_num
from customers
)
delete from customers_cte where row_num > 1;
There are many other ways to do a similar thing, I just jotted down the way I prefer to do it.