컴퓨터/MySQL

MySQL (17) - Join에서 중복을 제거하는 방법

달서비 2023. 10. 19. 22:29

SQL을 사용하다 보면 Join을 해서 테이블을 자주 합치게 됩니다. 데이터를 합칠 때 중복 값이 나올 수가 있습니다. DB를 관리할 때 보통 Join을 할때 대상이 유니크한 값을 가져야 합니다. 하지만 DB 관리를 잘못한 경우 중복이 발생할 수 있습니다. 이번에는 중복을 제거하는 방법에 대하여 알아보겠습니다. 다양한 방법들이 있으나 상황에 따라 사용하면 됩니다.

데이터 테이블 - Pixabay

예시 테이블

T01 (사번, 이름, 직급, 휴대폰번호)

STAF_NO STAF_NM STAF_LEVEL PHONE_NUM
1000 홍길동 팀장 010-1234-1234
1001 김철수 대리 010-1234-1235
1002 김영희 대리 010-1234-1236

T02 (사번, 직급, 근속일자, 월급)

STAF_NO STAF_LEVEL STAF_DATE STAF_MONEY
1000 팀장 20100101 10000000
1001 대리 20120301 4000000
1001 대리 20120301 4000000
1002 대리 20190301 3000000

 

조인을 없애는 방법

우선 해당 테이블을 LEFT JOIN을 하는 경우 다음과 같은 결과가 나옵니다.

SELECT *
FROM T01
LEFT OUTER JOIN T02
ON T01.STAF_NO = T02.STAF_NO
AND T01.STAF_LEVEL = T02.STAF_LEVEL
STAF_NO STAF_NM STAF_LEVEL PHONE_NUM STAF_DAE STAF_MONEY
1000 홍길동 팀장 010-1234-1234 20100101 10000000
1001 김철수 대리 010-1234-1235 20120301 4000000
1001 김철수 대리 010-1234-1235 20120301 4000000
1002 김영희 대리 010-1234-1236 20190301 3000000

여기서 중복이 일어나는 이유가 무엇일까요? 위에서 설명한 것과 같이 DB를 관리할 때 보통 Join을 할 때 대상이 유니크한 값을 가져야 하는데 그렇지 않기 때문에 중복이 발생하였습니다. 중복을 해결하는 방법들을 한가지씩 나열하겠습니다.

 

0. 테이블 간 제약조건 확인

위에서 유니크한 값을 가져야 한다고 했는데 그렇지 않았기 때문에 중복이 일어났습니다. 만약 데이터가 아래 경우에는 어떨까요?

STAF_NO STAF_LEVEL STAF_DATE STAF_MONEY
1000 팀장 20100101 10000000
1001 대리 20120301 4000000
1002 대리 20190301 3000000

해당 값은 중복 없이 유니크한 값을 가지고 있기 때문에 데이터에 중복이 발생하지 않습니다. 우선 중복이 일어나는 근본적인 원인을 파악하는 가장 좋은 방법은 제약조건을 확인하는 방법입니다. 다음 방법부터는 만약에 제약조건이 보장되지 않았을 때 해결하는 방법을 하나씩 소개하려고 합니다.

 

1. DISTINCT

SELECT DISTINCT *
FROM T01
LEFT OUTER JOIN T02
ON T01.STAF_NO = T02.STAF_NO
AND T01.STAF_LEVEL = T02.STAF_LEVEL
STAF_NO STAF_NM STAF_LEVEL PHONE_NUM STAF_DAE STAF_MONEY
1000 홍길동 팀장 010-1234-1234 20100101 10000000
1001 김철수 대리 010-1234-1235 20120301 4000000
1002 김영희 대리 010-1234-1236 20190301 3000000

중복을 제거하는 가장 단순한 방법은 Distinct를 이용하는 방법입니다. 단 한 단어만 추가하기 때문에 간단하게 쿼리문을 작성할 수 있습니다. 하지만 Distinct는 전체 데이터를 temp tablespace에 저장하고 처리하는 방식이라 시스템에 과부하를 줄 수 있습니다.

 

2. GROUP BY

SELECT T01.STAF_NO, T01.STAF_NM, T01.STAF_LEVEL, T01.PHONE_NUM, T02.STAF_DATE, T02.STAF_MONEY
FROM T01
LEFT OUTER JOIN T02 
ON T01.STAF_NO = T02.STAF_NO 
AND T01.STAF_LEVEL = T02.STAF_LEVEL
GROUP BY T01.STAF_NO, T01.STAF_NM, T01.STAF_LEVEL, T01.PHONE_NUM, T02.STAF_DATE, T02.STAF_MONEY

두 번째 방법은 Group By로 묶는 방법입니다. Group By는 데이터를 특정하게 묶는 방법으로 데이터 중복을 제거할 때 Select 절의 칼럼과 Group By 절의 칼럼이 일치해야 합니다. Distinct에 비하여 조금 더 성능이 좋습니다. 대신 쿼리문이 많이 길어집니다.

 

3. Rank

SELECT T01.STAF_NO, T01.STAF_NM, T01.STAF_LEVEL, T01.PHONE_NUM, T02.STAF_DATE, T02.STAF_MONEY
FROM T01
LEFT OUTER JOIN (
	SELECT STAF_NO, STAF_LEVEL, STAF_DATE, STAF_MONEY,
           RANK() OVER (PARTITION BY STAF_NO, STAF_LEVEL ORDER BY STAF_DATE) AS STAF_RANK
	FROM T02
) T02 
ON T01.STAF_NO = T02.STAF_NO 
AND T01.STAF_LEVEL = T02.STAF_LEVEL
WHERE T02.STAF_RANK = 1

마지막으로 RANK 함수를 이용하는 방법입니다. RANK 함수를 통하여 순위를 선정하게 됩니다. 순위의 기준을 JOIN으로 묶는 값을 두는 경우 중복된 값은 1위 2위 등 여러 순위를 가지게 됩니다. 그중 1위만 출력되게 하면 자연스럽게 중복이 제거됩니다.