반응형
오늘 문제 풀다가 두 가지를 새로 알았다.
- 테이블을 자기 자신과 조인(Self Join)할 수 있다
- WITH 문(CTE)로 임시 테이블을 만들어 단계별로 쿼리를 짤 수 있다
이 두 가지를 “전날 온도와 비교해서 더 따뜻했던 날짜의 id를 구하는 문제”로 정리해본다.
문제 요약
Weather(id, recordDate, temperature) 테이블이 있다.
각 날짜의 온도가 전날보다 높았으면 그 날짜의 id를 반환하라.
- recordDate는 날짜,
- 날짜는 중복 없음(= 하루에 한 행)
스키마 (예시)
| ID | recordDate | temperature |
| 1 | 2021-01-01 | 10 |
| 2 | 2021-01-02 | 25 |
| 3 | 2021-01-03 | 20 |
| 4 | 2021-01-04 | 30 |
정답은 2, 4 (각각 전날보다 따뜻함)
방법 1) Self Join (자기 자신과 조인)
MySQL 버전 (DATEDIFF 이용)
SELECT w1.id
FROM Weather w1
JOIN Weather w2
ON DATEDIFF(w1.recordDate, w2.recordDate) = 1
WHERE w1.temperature > w2.temperature;
핵심 아이디어
- 같은 테이블을 두 번 부른다: 오늘(w1) vs 어제(w2)
- DATEDIFF(today, yesterday) = 1이면 날짜가 정확히 하루 차이
- 온도 비교해서 오늘이 더 크면 w1.id 반환
다른 DB 호환 팁
- MySQL(대안): w1.recordDate = DATE_ADD(w2.recordDate, INTERVAL 1 DAY)
- PostgreSQL: w1.recordDate = w2.recordDate + INTERVAL '1 day'
- Oracle: w1.recordDate = w2.recordDate + 1 (날짜 + 정수 = 일수 더하기)
- SQL Server: w1.recordDate = DATEADD(day, 1, w2.recordDate)
방법 2) WITH 문(CTE)로 “복사” 후 조인
CTE(공통 테이블 표현식)는 쿼리 안에서만 쓰는 임시 테이블이라고 보면 편하다.
WITH w AS (
SELECT id, recordDate, temperature
FROM Weather
)
SELECT a.id
FROM w a
JOIN w b
ON DATEDIFF(a.recordDate, b.recordDate) = 1
WHERE a.temperature > b.temperature;
느낌
- Weather를 w라는 이름으로 임시 저장
- 읽기 쉬움(가독성 👍), 복잡한 쿼리를 단계로 쪼갤 때 유용
✅ CTE 지원 여부
- RDB 대부분 지원(O): Oracle(11g+), MySQL(8.0+), MariaDB(10.2+), PostgreSQL, SQL Server, SQLite
- NoSQL(Mongo 등)은 SQL이 아니라서 CTE 자체는 없음(대신 Aggregation Pipeline 사용)
보너스) 윈도우 함수로 한 방에 (MySQL 8.0+, PostgreSQL, Oracle 등)
LAG로 “이전 행의 값”을 끌어와 비교한다.
SELECT id
FROM (
SELECT id,
recordDate,
temperature,
LAG(temperature) OVER (ORDER BY recordDate) AS prev_temp
FROM Weather
) t
WHERE temperature > prev_temp;
장점
- 조인 없이도 “전날 값”을 바로 비교 (깔끔함)
- 정렬 기준만 정확하면 구현이 매우 간단
내가 몰랐던 포인트 (정리)
- Self Join 가능조인 조건만 잘 걸어주면 된다.
- 같은 테이블을 두 번 가져와서 “오늘 vs 어제”처럼 서로 비교할 수 있다.
- WITH(CTE)
- 긴 서브쿼리를 깔끔하게 이름 붙여서 재사용
- 단계별로 쿼리를 나눌 때 가독성/유지보수성 압승
- MySQL 8.0 이상부터 사용 가능(5.x는 불가!)
- 쿼리 안에서만 쓰는 임시 테이블.
- 윈도우 함수(LAG)다만 DB 버전/엔진에 따라 지원 여부가 다르니 확인 필요.
- “이전 행” 비교는 사실 조인 없이도 된다.
실무 주의사항
- 날짜 구멍(Gap): 전날 데이터가 아예 없으면(예: 주말 제외 데이터) self join/LAG 모두 비교 불가 → 해당 행은 결과에서 빠지는 게 정상
- 인덱스: recordDate에 인덱스를 주면 조인/정렬 성능이 좋아짐
- 타임존/타입: recordDate가 DATE인지 DATETIME인지에 따라 비교 함수 주의
TL;DR
- 전날 비교 문제는 Self Join(가장 범용적) 또는 LAG(가독성 최고)로 해결
- **WITH(CTE)**로 쿼리를 단계적으로 써주면 읽기 좋고 유지보수 편함
- DB/버전에 따라 함수가 살짝 다를 수 있으니 문법만 맞춰주면 끝!
반응형
'Database' 카테고리의 다른 글
| [SQL] CROSS JOIN과 LEFT JOIN으로 “모든 학생 × 모든 과목” 응시 횟수 구하기 (0) | 2025.10.21 |
|---|---|
| [DB] MySQL 테이블 오류 및 해결: "'Incorrect key file for table' (0) | 2024.01.30 |
| [DB] Database 정규화 (1NF,2NF,3NF,BCNF) 👨💻 (0) | 2023.02.07 |
| [SQL] 삭제하기! (DELETE, TRUNCATE, DROP) (0) | 2023.02.02 |
| [SQL] 필드명이 예약어일 경우...!! (0) | 2023.01.13 |
댓글