요일별 매출 집계나 "주말 주문만 뽑기" 같은 쿼리를 짤 때 MySQL에서 요일 번호를 구하는 함수는 DAYOFWEEK()와 WEEKDAY() 두 가지가 있습니다. 이름만 보면 비슷한데 반환하는 숫자 체계가 완전히 달라서, 어느 쪽을 썼는지 헷갈리면 결과가 하루씩 밀립니다.

언어마다 요일 번호가 다르다

요일 번호를 매기는 방식은 크게 두 가지가 있습니다. 하나는 일요일을 0으로 시작하는 방식으로, C 계열 언어나 자바스크립트의 getDay(), .NET의 DayOfWeek 열거형이 이렇게 동작합니다.

일 월 화 수 목 금 토
0 1 2 3 4 5 6

다른 하나는 ODBC 표준 방식으로, 일요일을 1로 시작합니다. MySQL의 DAYOFWEEK()가 이 체계를 따르고, VBA의 Weekday() 함수도 기본값으로 쓰면 같은 숫자가 나옵니다.

일 월 화 수 목 금 토
1 2 3 4 5 6 7

WEEKDAY()는 월요일이 0

문제는 WEEKDAY()입니다. 이 함수는 ODBC 표준을 따르지 않고 월요일을 0으로 시작합니다. 그래서 일요일이 맨 끝 6이 됩니다.

월 화 수 목 금 토 일
0 1 2 3 4 5 6

같은 날짜를 넣어도 DAYOFWEEK()와 WEEKDAY()가 돌려주는 값은 다르고, 차이가 일정한 숫자만큼 나는 것도 아닙니다. 예를 들어 월요일은 DAYOFWEEK()가 2, WEEKDAY()가 0이고, 일요일은 각각 1과 6입니다. 주말을 거르는 조건을 DAYOFWEEK(주문일) IN (1, 7)로 써야 할 것을 WEEKDAY()로 함수 이름만 바꿔 쓰면 1은 화요일, 7은 없는 값이라 화요일만 걸리고 주말은 빠지는 실수가 나옵니다.

직접 확인해 보려면 오늘 날짜로 세 값을 한 번에 찍어 보면 됩니다.

SELECT DATE_FORMAT(NOW(),"%Y-%m-%d"),WEEKDAY(NOW()), DAYOFWEEK(NOW());

오늘 날짜와 WEEKDAY, DAYOFWEEK 결과를 함께 조회한 화면

어느 쪽을 쓸까

특별한 이유가 없다면 DAYOFWEEK()를 쓰는 게 실수가 적습니다. ODBC 표준이라 VBA나 엑셀 쪽과 숫자가 맞고, 다른 DB나 리포트 도구와 주고받을 때도 같은 체계일 가능성이 높습니다. WEEKDAY()는 월요일부터 한 주를 세는 업무, 예를 들어 "이번 주 월요일 날짜"를 구할 때 날짜 - INTERVAL WEEKDAY(날짜) DAY처럼 쓰면 편해서, 그런 용도일 때만 골라 쓰면 됩니다.

PHP나 VB.NET에서 받은 요일 값을 SQL 조건에 넣는 경우도 조심해야 합니다. 앱 쪽은 일요일=0, DB 쪽 DAYOFWEEK()는 일요일=1이라 그대로 비교하면 하루가 어긋납니다. 요일 이름이 필요하면 숫자를 변환하지 말고 DAYNAME()이나 DATE_FORMAT(날짜, '%W')로 바로 영문 요일명을 받는 방법도 있습니다. 참고로 DATE_FORMAT의 %w는 일요일=0 체계라서, 이것까지 섞이면 한 쿼리 안에 세 가지 번호 체계가 공존하게 되니 한 프로젝트 안에서는 하나로 통일해 두는 게 좋습니다.

참고: MySQL 8.0 Reference Manual - Date and Time Functions