SQL 튜터 세션 정리

SQL
LeetCode
MySQL
Date Function
LeetCode 197 Rising Temperature에서 날짜 차이 비교와 DATE_SUB, DATE_ADD, DATEDIFF를 이해한 기록
Published

2026.06.05

오늘 푼 문제

  • 문제: LeetCode 197. Rising Temperature
  • 핵심 개념: 날짜 기준 self join, 하루 전 날짜 비교, MySQL 날짜 함수
  • 사용 표현: DATE_SUB(), DATE_ADD(), DATEDIFF()

문제 이해

Weather 테이블에서 전날보다 온도가 높은 날의 id를 찾는 문제다.

중요한 점은 단순히 이전 행과 비교하는 것이 아니라, recordDate 기준으로 정확히 하루 전 날짜와 비교해야 한다는 것이다.

예를 들어 다음처럼 날짜가 중간에 비어 있을 수 있다.

2021-01-01  10
2021-01-03  15

이 경우 2021-01-03의 바로 이전 행은 2021-01-01이지만, 실제 하루 전 날짜인 2021-01-02의 데이터는 없다. 따라서 이 두 행을 비교하면 안 된다.

처음 접근: 순위로 이전 일을 찾기

처음에는 날짜 순서대로 순위를 만들고, 현재 행의 순위보다 1 작은 행을 전날처럼 붙이는 방식으로 접근했다.

WITH Tmp AS (
    SELECT id, recordDate, temperature, RANK() OVER(ORDER BY recordDate) AS rnk
    FROM Weather
)
SELECT id
FROM (
    SELECT w1.id,
           w1.recordDate,
           w1.temperature,
           w2.temperature AS yesterday_temperature
    FROM Tmp w1
    LEFT JOIN Tmp w2
      ON w1.rnk - 1 = w2.rnk
) AS t
WHERE temperature > yesterday_temperature;

이 접근은 self join으로 비교 대상을 붙인다는 점에서는 좋다. 하지만 rnk - 1이전 행을 의미할 뿐, 정확히 하루 전 날짜를 의미하지 않는다.

따라서 날짜가 연속되어 있지 않은 데이터에서는 오답이 될 수 있다.

두 번째 접근: recordDate - 1

다음처럼 날짜에서 1을 빼서 어제 날짜를 만들려고 했다.

SELECT id
FROM (
    SELECT w1.id,
           w1.recordDate,
           w1.temperature,
           w2.temperature AS yesterday_temperature
    FROM Weather w1
    LEFT JOIN Weather w2
      ON w1.recordDate - 1 = w2.recordDate
) AS t
WHERE temperature > yesterday_temperature;

겉으로는 recordDate - 1이 “날짜에서 하루 빼기”처럼 보이지만, MySQL에서는 날짜 연산으로 안전하게 처리되지 않는다.

날짜에 숫자를 직접 빼면 날짜 타입 연산이 아니라 숫자처럼 변환되어 계산될 수 있다. 특히 월이나 연도가 바뀌는 경계에서 문제가 생긴다.

예를 들어 우리가 원하는 것은 다음과 같다.

2015-01-01 - 1일 = 2014-12-31

하지만 단순히 recordDate - 1처럼 쓰면 이런 날짜 경계를 안정적으로 처리한다고 보기 어렵다. 날짜는 날짜 함수로 계산하는 것이 안전하다.

최종 풀이 1: DATE_ADD() 사용

SELECT w1.id
FROM Weather w1
JOIN Weather w2
  ON w1.recordDate = DATE_ADD(w2.recordDate, INTERVAL 1 DAY)
WHERE w1.temperature > w2.temperature;

의미는 다음과 같다.

어제 날짜 + 1일 = 오늘 날짜

w2를 어제 데이터, w1을 오늘 데이터로 보고 연결한다.

최종 풀이 2: DATE_SUB() 사용

SELECT w1.id
FROM Weather w1
JOIN Weather w2
  ON DATE_SUB(w1.recordDate, INTERVAL 1 DAY) = w2.recordDate
WHERE w1.temperature > w2.temperature;

의미는 다음과 같다.

오늘 날짜 - 1일 = 어제 날짜

처음에 시도했던 w1.recordDate - 1 = w2.recordDate와 의도는 같지만, DATE_SUB()를 사용하면 MySQL이 날짜 타입에 맞게 하루 전 날짜를 계산한다.

최종 풀이 3: DATEDIFF() 사용

SELECT w1.id
FROM Weather w1
JOIN Weather w2
  ON DATEDIFF(w1.recordDate, w2.recordDate) = 1
WHERE w1.temperature > w2.temperature;

의미는 다음과 같다.

w1 날짜 - w2 날짜 = 1일

w1w2보다 정확히 하루 뒤인 경우만 연결한다.

날짜 함수 정리

DATE_SUB()

DATE_SUB()는 날짜에서 일정 기간을 빼는 함수다.

DATE_SUB(날짜, INTERVAL 숫자 단위)

예시:

DATE_SUB('2026-06-05', INTERVAL 1 DAY)

결과:

2026-06-04

이번 문제에서는 “오늘 날짜에서 하루를 빼서 어제 날짜를 찾는 방식”으로 사용할 수 있다.

DATE_SUB(w1.recordDate, INTERVAL 1 DAY) = w2.recordDate

DATE_ADD()

DATE_ADD()는 날짜에 일정 기간을 더하는 함수다.

DATE_ADD(날짜, INTERVAL 숫자 단위)

예시:

DATE_ADD('2026-06-04', INTERVAL 1 DAY)

결과:

2026-06-05

이번 문제에서는 “어제 날짜에 하루를 더하면 오늘 날짜가 되는 방식”으로 사용할 수 있다.

w1.recordDate = DATE_ADD(w2.recordDate, INTERVAL 1 DAY)

DATEDIFF()

DATEDIFF()는 두 날짜 사이의 일수 차이를 구하는 함수다.

DATEDIFF(날짜1, 날짜2)

예시:

DATEDIFF('2026-06-05', '2026-06-04')

결과:

1

이번 문제에서는 두 날짜의 차이가 정확히 1일인 경우만 연결하면 된다.

DATEDIFF(w1.recordDate, w2.recordDate) = 1

LEFT JOIN이 꼭 필요할까?

이 문제에서는 JOIN, 즉 INNER JOIN을 써도 충분하다.

어제 데이터가 없는 날은 비교 대상이 없으므로 결과에 포함될 수 없다. LEFT JOIN을 사용하더라도 어제 온도는 NULL이 되고, 다음 조건에서 탈락한다.

WHERE temperature > yesterday_temperature

NULL과의 비교 결과는 참이 아니기 때문이다.

따라서 의도를 더 명확하게 표현하려면 JOIN을 사용하는 편이 좋다.

오늘의 메타 정리

잘한 점

  • “오늘 행과 어제 행을 붙여서 비교한다”는 self join 구조를 떠올렸다.
  • yesterday_temperature를 따로 붙여 비교하려는 사고가 명확했다.
  • 처음 쿼리에서 막힌 이유를 질문하며 날짜 연산의 원리를 확인했다.

실수 패턴

  • RANK()로 만든 이전 행을 전날로 해석했다.
  • recordDate - 1을 날짜에서 하루 빼는 연산으로 생각했다.

핵심 인사이트

SQL에서 날짜 문제를 풀 때는 “이전 행”과 “이전 날짜”를 구분해야 한다. 날짜는 연속되어 있지 않을 수 있으므로, 순서 기반 비교보다 날짜 차이 조건을 명시하는 것이 안전하다.

다음에 공부할 것