MySQL에서 동일한 값이 여러 번 저장된 중복 레코드는 데이터의 신뢰성을 떨어뜨리고 저장 공간을 낭비합니다. 이 글에서는 LEFT JOIN과 GROUP BY, MIN() 함수를 조합하여 중복 값을 손쉽게 제거하는 방법을 실제 예제와 함께 단계별로 살펴보겠습니다.
1. 테이블 생성
먼저 실습에 사용할 테이블을 생성합니다.
mysql> create table DemoTable
(
Id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
FirstName varchar(100)
);
Query OK, 0 rows affected (0.46 sec)Id 컬럼은 AUTO_INCREMENT로 설정되어 각 레코드가 고유한 번호를 가지며, FirstName 컬럼에는 이름이 저장됩니다.
2. 샘플 데이터 삽입
INSERT 문을 사용하여 의도적으로 중복된 이름을 포함한 레코드를 입력합니다.
mysql> insert into DemoTable(FirstName) values('Chris');
Query OK, 1 row affected (0.18 sec)
mysql> insert into DemoTable(FirstName) values('Robert');
Query OK, 1 row affected (0.12 sec)
mysql> insert into DemoTable(FirstName) values('Robert');
Query OK, 1 row affected (0.07 sec)
mysql> insert into DemoTable(FirstName) values('John');
Query OK, 1 row affected (0.14 sec)
mysql> insert into DemoTable(FirstName) values('John');
Query OK, 1 row affected (0.11 sec)
mysql> insert into DemoTable(FirstName) values('Mike');
Query OK, 1 row affected (0.09 sec)3. 현재 데이터 확인
SELECT 문으로 전체 레코드를 조회하면 다음과 같습니다.
mysql> select *from DemoTable;
실행 결과:
+----+-----------+ | Id | FirstName | +----+-----------+ | 1 | Chris | | 2 | Robert | | 3 | Robert | | 4 | John | | 5 | John | | 6 | Mike | +----+-----------+ 6 rows in set (0.00 sec)
'Robert'와 'John'이 각각 두 번씩 저장되어 있어 총 6개의 레코드가 존재합니다.
4. LEFT JOIN으로 중복 제거하기
다음은 중복 값을 제거하는 핵심 쿼리입니다.
mysql> delete tbl from DemoTable tbl
left join(
select min(Id) as Id, FirstName
from DemoTable
group by FirstName
) tbl1 ON tbl.Id = tbl1.Id AND tbl.FirstName = tbl1.FirstName
where tbl1.Id IS NULL;
Query OK, 2 rows affected (0.16 sec)쿼리 동작 원리
이 쿼리의 작동 방식은 다음과 같습니다.
① 서브쿼리: FirstName 기준으로 GROUP BY를 수행하고, 각 그룹에서 MIN(Id), 즉 가장 작은 Id를 선택합니다. 이렇게 하면 각 이름별로 '대표 레코드' 한 개만 남게 됩니다.
② LEFT JOIN: 원본 테이블(tbl)을 서브쿼리 결과(tbl1)와 Id 및 FirstName 기준으로 LEFT JOIN합니다. 대표 레코드는 매칭되지만, 나머지 중복 레코드는 매칭되지 않아 tbl1.Id가 NULL이 됩니다.
③ DELETE: WHERE 절에서 tbl1.Id IS NULL인 행, 즉 그룹 내 최소 Id가 아닌 중복 레코드만 삭제합니다.
5. 삭제 후 결과 확인
다시 한번 테이블을 조회해 보겠습니다.
mysql> select *from DemoTable;
실행 결과:
+----+-----------+ | Id | FirstName | +----+-----------+ | 1 | Chris | | 2 | Robert | | 4 | John | | 6 | Mike | +----+-----------+ 4 rows in set (0.00 sec)
중복된 'Robert'(Id 3)와 'John'(Id 5)이 삭제되고, 각 이름당 가장 작은 Id를 가진 레코드만 남아 총 4개의 레코드가 조회됩니다.
마무리
이처럼 LEFT JOIN과 GROUP BY, MIN() 함수를 활용하면 별도의 임시 테이블 없이 하나의 DELETE 문으로 중복 데이터를 깔끔하게 정리할 수 있습니다. 참고로 MySQL 8.0 이상에서는 윈도우 함수인 ROW_NUMBER()를 사용하는 방법도 있으니, 상황에 맞게 선택하여 활용하시기 바랍니다.