데이터베이스 작업을 하다 보면 중복된 값이 존재하는 행들 중에서 가장 최근(최대) 날짜만 조회해야 하는 경우가 자주 있습니다. 이럴 때는 SQL의 GROUP BY 절과 HAVING 절을 함께 사용하면 간단하게 해결할 수 있습니다.
이번 글에서는 실제 예제를 통해 학생 이름별로 중복된 데이터를 찾고, 각 이름에 해당하는 마감일(DueDate) 중 가장 늦은 날짜를 출력하는 방법을 단계별로 살펴보겠습니다.
1. 예제 테이블 생성
먼저 실습에 사용할 테이블을 생성합니다. 학생 이름(StudentName)과 마감일(DueDate) 두 개의 컬럼으로 구성된 간단한 테이블입니다.
mysql> create table DemoTable
(
StudentName varchar(100),
DueDate date
);
Query OK, 0 rows affected (0.72 sec)2. 샘플 데이터 삽입
다음으로 INSERT 명령을 사용해 테이블에 여러 개의 레코드를 추가합니다. 의도적으로 John, Chris, Bob, Robert의 이름이 중복되도록 데이터를 구성했습니다.
mysql> insert into DemoTable values('John','2019-01-11');
Query OK, 1 row affected (0.26 sec)
mysql> insert into DemoTable values('Chris','2019-02-11');
Query OK, 1 row affected (0.20 sec)
mysql> insert into DemoTable values('Chris','2019-03-11');
Query OK, 1 row affected (0.19 sec)
mysql> insert into DemoTable values('John','2019-04-11');
Query OK, 1 row affected (0.12 sec)
mysql> insert into DemoTable values('Bob','2019-05-11');
Query OK, 1 row affected (0.17 sec)
mysql> insert into DemoTable values('Bob','2019-06-11');
Query OK, 1 row affected (0.15 sec)
mysql> insert into DemoTable values('Robert','2019-07-11');
Query OK, 1 row affected (0.18 sec)
mysql> insert into DemoTable values('Robert','2019-08-11');
Query OK, 1 row affected (0.17 sec)
mysql> insert into DemoTable values('Robert','2019-09-11');
Query OK, 1 row affected (0.15 sec)3. 전체 데이터 확인
SELECT 문을 실행해 테이블에 저장된 모든 레코드를 확인해 보겠습니다.
mysql> select *from DemoTable;
출력 결과
+-------------+------------+ | StudentName | DueDate | +-------------+------------+ | John | 2019-01-11 | | Chris | 2019-02-11 | | Chris | 2019-03-11 | | John | 2019-04-11 | | Bob | 2019-05-11 | | Bob | 2019-06-11 | | Robert | 2019-07-11 | | Robert | 2019-08-11 | | Robert | 2019-09-11 | +-------------+------------+ 9 rows in set (0.00 sec)
출력 결과를 보면 총 9개의 레코드가 있으며, 네 명의 학생 모두 두 번 이상 등장하는 것을 알 수 있습니다.
4. 중복 값과 최대 날짜 조회 쿼리
이제 핵심인 쿼리입니다. 아래 쿼리는 GROUP BY로 학생 이름별로 그룹화한 뒤, HAVING COUNT(*) > 1 조건을 통해 두 번 이상 나타나는(즉, 중복되는) 이름만 필터링하고, MAX() 함수로 각 그룹의 가장 늦은 마감일을 반환합니다.
mysql> select tbl.StudentName,max(tbl.DueDate) from DemoTable tbl group by tbl.StudentName having count(*) > 1;
출력 결과
+-------------+------------------+ | StudentName | max(tbl.DueDate) | +-------------+------------------+ | John | 2019-04-11 | | Chris | 2019-03-11 | | Bob | 2019-06-11 | | Robert | 2019-09-11 | +-------------+------------------+ 4 rows in set (0.00 sec)
정리
실행 결과를 보면 중복된 이름을 가진 4명의 학생이 각각 한 번씩만 출력되었고, 그 옆에는 해당 학생의 마감일 중 가장 최신 날짜가 표시된 것을 확인할 수 있습니다.
핵심 포인트를 정리하면 다음과 같습니다.
GROUP BY: 중복 판단 기준이 되는 컬럼(여기서는 StudentName)으로 데이터를 그룹화합니다.HAVING COUNT(*) > 1: 그룹화된 결과 중 레코드 수가 2개 이상인 것, 즉 중복된 값만 남깁니다.MAX(): 각 그룹 내에서 날짜 컬럼의 최대값(가장 최근 날짜)을 추출합니다.
이 패턴은 주문 이력에서 고객별 최근 주문일을 찾거나, 로그 데이터에서 사용자별 마지막 접속일을 집계하는 등 다양한 실무 상황에서 응용할 수 있으니 꼭 기억해 두시기 바랍니다.