문제 요약
코로나 검사 기록 테이블에서
- 양성(Positive) 판정을 받은 뒤
- 음성(Negative) 판정을 받은 환자
를 찾고,
최초 양성일과 최초 음성일 사이의 회복 기간(Day)을 계산하는 문제였다.
내가 처음 접근한 방법
처음에는
ROW_NUMBER()
를 사용해서
환자별 가장 최근 검사 결과를 찾으려고 했다.
이유는
현재 상태가 Negative인지 확인해야 한다
고 생각했기 때문이다.
하지만 문제는
현재 상태
X
양성 → 음성 변화 과정
을 찾는 것이 핵심이었다.
따라서 최신 기록만 찾는 방식으로는 해결되지 않았다.
최종 정답 SQL
SELECT
p.patient_id,
MIN(p.test_date) AS first_positive_date,
MIN(n.test_date) AS first_negative_date,
DATEDIFF(
MIN(n.test_date),
MIN(p.test_date)
) AS recovery_days
FROM covid_tests p
JOIN covid_tests n
ON p.patient_id = n.patient_id
AND p.result = 'Positive'
AND n.result = 'Negative'
AND p.test_date < n.test_date
GROUP BY p.patient_id
ORDER BY recovery_days;
SQL 실행 순서
1단계
FROM covid_tests p
양성 기록 후보 생성
2단계
JOIN covid_tests n
음성 기록 후보 생성
3단계
ON
p.patient_id = n.patient_id
같은 환자끼리 연결
4단계
p.result = 'Positive'
AND n.result = 'Negative'
양성 → 음성 관계만 유지
5단계
p.test_date < n.test_date
음성이 양성보다 늦게 발생한 경우만 유지
6단계
GROUP BY patient_id
환자별 집계
7단계
MIN(p.test_date)
MIN(n.test_date)
최초 양성일
최초 음성일 계산
8단계
DATEDIFF()
회복 기간 계산
9단계
ORDER BY recovery_days
회복 기간 기준 정렬
핵심 SQL 개념 정리
Self Join
문제 상황
같은 테이블 안에서
Positive
↓
Negative
관계를 찾아야 했다.
사용 이유
한 테이블 내부의 서로 다른 행을 비교해야 하기 때문
동작 방식
covid_tests
↓
Positive 집합(p)
+
Negative 집합(n)
↓
같은 환자끼리 연결
↓
상태 변화 추적
MIN()
문제 상황
최초 양성일과 최초 음성일을 찾아야 했다.
사용 이유
회복 기간은
최초 음성일
-
최초 양성일
이기 때문이다.
사용 예시
MIN(test_date)
INNER JOIN 조건절 필터링
사용 예시
ON p.patient_id = n.patient_id
AND p.result = 'Positive'
AND n.result = 'Negative'
AND p.test_date < n.test_date
장점
JOIN 후 WHERE
보다
필요한 관계만 JOIN
하는 구조라 가독성이 좋다.
함수 비교 정리
ROW_NUMBER() vs MIN()
내가 사용한 함수
ROW_NUMBER()
목적
최신 검사 결과 찾기
정답 함수
MIN()
목적
최초 양성일
최초 음성일
찾기
차이
함수목적
| ROW_NUMBER() | 순위 부여 |
| MIN() | 최솟값 조회 |
왜 MIN()이 더 적절했는가
문제는
최신 상태
X
최초 양성일과 최초 음성일
을 구해야 했기 때문이다.
TIMESTAMPDIFF() vs DATEDIFF()
내가 떠올린 함수
TIMESTAMPDIFF()
정답 함수
DATEDIFF()
차이
함수특징
| DATEDIFF | 날짜 차이(일 단위) |
| TIMESTAMPDIFF | 원하는 단위 지정 가능 |
예시
DATEDIFF(
'2024-01-10',
'2024-01-01'
)
TIMESTAMPDIFF(
DAY,
'2024-01-01',
'2024-01-10'
)
결과
9
왜 DATEDIFF가 더 적절했는가
이번 문제는
일(day)
차이만 필요했다.
따라서
DATEDIFF()
가 더 짧고 직관적이다.
반면 세션 길이, 체류시간 같은 문제라면
TIMESTAMPDIFF(SECOND)
가 적합하다.
오늘 배운 점
- 상태 변화 추적 문제는 Self Join을 먼저 의심한다.
- 최신 상태를 찾는 문제와 최초 발생일을 찾는 문제는 완전히 다르다.
- 날짜 차이만 계산한다면 DATEDIFF가 가장 간단하다.
- JOIN 조건절에서 필요한 관계를 먼저 제한하면 쿼리가 명확해진다.
다음에 같은 문제를 만나면
상태 변화 추적 → Self Join
최초 발생 시점 → MIN()
최신 상태 → ROW_NUMBER()
를 먼저 검토한다.
핵심 한 줄 요약
이 문제는 최신 상태를 찾는 문제가 아니라,
동일 환자의 Positive → Negative 변화 관계를 Self Join으로 연결하고
MIN()과 DATEDIFF()로 회복 기간을 계산하는 문제였다.
'TIL' 카테고리의 다른 글
| [TIL172] leetcode - Find Overbooked Employees (0) | 2026.06.25 |
|---|---|
| [TIL171] leetcode - Find Drivers with Improved Fuel Efficiency (0) | 2026.06.24 |
| [TIL169] HackerRank - Type of Triangle (0) | 2026.06.24 |
| [TIL168] solvesql - 세 명의 사용자가 서로 친구인 관계 찾기 (Triangle 관계 탐색) (0) | 2026.06.23 |
| [TIL167] solvesql - 유량(flow)과 저량(stock) (0) | 2026.06.23 |