9월 매출을 BETWEEN으로 뽑았더니 마지막 날 주문이 통째로 빠진 이유
문제 발생
월간 정산 쿼리를 이렇게 짰습니다. 9월 1일부터 30일까지니까 BETWEEN이면 깔끔하다고 생각했습니다.
SELECT SUM(amount)
FROM orders
WHERE created_at BETWEEN '2026-09-01' AND '2026-09-30';created_at은 DATETIME 컬럼입니다. 결제 대시보드의 합계와 맞춰 보니 숫자가 계속 모자랐고, 차이를 따라가 보니 9월 30일 0시 이후 주문이 통째로 빠져 있었습니다. 한 달 중 하루가 그대로 사라진 셈이었습니다.
원인 분석
날짜만 적으면 그날 0시를 뜻합니다. MariaDB 문서의 BETWEEN 항목이 이 경우를 따로 짚어 둡니다 — 시간 부분을 생략하면 00:00과 비교하므로, 같은 날짜의 그 이후 시각은 반환되지 않는다고요. 문서 예시가 정확히 이 모양입니다. DATE 컬럼에 BETWEEN '2018-11-11' AND '2018-11-12'를 걸면 두 행이 다 나오는데, 같은 날짜를 가진 DATETIME 컬럼(2018-11-12 05:15:00)에 걸면 11일 행 하나만 나옵니다.
MySQL 문서를 보면 이유가 더 분명해집니다. DATE 값을 DATETIME으로 바꾸면 시간 정보가 없으니 '00:00:00'이 붙습니다. 그리고 BETWEEN은 인자 타입이 같을 때 min <= expr AND expr <= max와 같습니다. 결국 위 쿼리의 끝 조건은 created_at <= '2026-09-30 00:00:00'이었던 겁니다.
DATE 컬럼이었다면 아무 문제 없었을 쿼리라서, 다른 테이블에서 잘 돌던 패턴을 그대로 가져다 쓴 게 화근이었습니다.
해결 방안
- 끝을 "다음 날 0시 미만"으로 씁니다. 시작은 포함하고 끝은 포함하지 않는 범위로 바꾸면, 컬럼에 시간이 있든 없든 신경 쓸 일이 없어집니다.
WHERE created_at >= '2026-09-01'
AND created_at < '2026-10-01'-
'23:59:59'로 막지 않습니다. 끝을'2026-09-30 23:59:59'로 바꾸면 당장은 맞아 보입니다. 하지만 MariaDB의DATETIME은 소수점 아래 최대 6자리까지 정밀도를 가질 수 있습니다(지정하지 않으면 0).DATETIME(6)컬럼이라면23:59:59.5에 들어온 주문은 또 빠집니다. 나중에 누가 컬럼 정밀도를 올리는 순간 조용히 틀어지는 쿼리가 됩니다. -
애플리케이션에서 넘길 때도 같은 모양을 지킵니다. "9월"을 입력받으면
2026-09-01과2026-10-01을 만들어>=,<로 넘깁니다. 이렇게 하면 그달 마지막 날이 30일인지 31일인지 계산할 필요도 없어집니다. -
BETWEEN을 꼭 써야 한다면 타입을 명시합니다. MySQL 문서는 날짜·시간 값에BETWEEN을 쓸 때CAST()로 원하는 타입을 명시하라고 권하고,DATETIME을 두DATE값과 비교한다면DATE를DATETIME으로 바꾸라고 합니다. 바꾸고 나면 끝값이00:00:00이라는 게 쿼리에 그대로 드러나서, 적어도 같은 실수를 눈으로 잡을 수 있습니다. -
경계값을 테스트로 박아 둡니다.
9월 30일 23:59:59.5와10월 1일 00:00:00두 건을 넣고, 9월 합계에 앞의 것만 잡히는지 봅니다. 월 경계는 한 달에 한 번만 드러나는 버그라 테스트가 아니면 다음 정산까지 모릅니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.