DB

Oracle, MySQL, MSSQL 날짜 함수 완벽 비교 가이드

shaprimanDev 2025. 5. 24. 22:01
반응형

데이터베이스에서 날짜와 시간 처리는 매우 중요한 기능 중 하나입니다. 하지만 Oracle, MySQL, MS SQL Server는 각각 다른 날짜 함수와 문법을 제공하여, 개발자들이 다른 데이터베이스로 마이그레이션할 때 가장 혼란스러워하는 부분 중 하나입니다. 각 데이터베이스 시스템의 날짜 함수 차이점과 대체 방법을 상세히 비교해보겠습니다.

Oracle
MySQL
MS SQL Server

🕐 1. 현재 날짜/시간 구하기

가장 기본적인 현재 날짜와 시간을 구하는 함수부터 각 데이터베이스마다 다릅니다.

기능 Oracle MySQL MS SQL Server
현재 날짜+시간 SYSDATE
SYSTIMESTAMP
NOW()
CURRENT_TIMESTAMP
GETDATE()
CURRENT_TIMESTAMP
현재 날짜만 TRUNC(SYSDATE) CURDATE()
CURRENT_DATE
CAST(GETDATE() AS DATE)
현재 시간만 TO_CHAR(SYSDATE, 'HH24:MI:SS') CURTIME()
CURRENT_TIME
CAST(GETDATE() AS TIME)

Oracle 예제

-- 현재 날짜/시간 SELECT SYSDATE FROM dual; -- 결과: 2025-01-15 14:30:25 -- 타임스탬프 (밀리초 포함) SELECT SYSTIMESTAMP FROM dual; -- 결과: 2025-01-15 14:30:25.123456 +09:00 -- 현재 날짜만 SELECT TRUNC(SYSDATE) FROM dual; -- 결과: 2025-01-15 00:00:00

MySQL 예제

-- 현재 날짜/시간 SELECT NOW(); -- 결과: 2025-01-15 14:30:25 -- 현재 날짜만 SELECT CURDATE(); -- 결과: 2025-01-15 -- 현재 시간만 SELECT CURTIME(); -- 결과: 14:30:25

MS SQL Server 예제

-- 현재 날짜/시간 SELECT GETDATE(); -- 결과: 2025-01-15 14:30:25.123 -- 현재 날짜만 SELECT CAST(GETDATE() AS DATE); -- 결과: 2025-01-15 -- 현재 시간만 SELECT CAST(GETDATE() AS TIME); -- 결과: 14:30:25.1230000

➕ 2. 날짜 연산 (더하기/빼기)

날짜에 일, 월, 년을 더하거나 빼는 방법도 각 데이터베이스마다 완전히 다릅니다.

연산 Oracle MySQL MS SQL Server
일 더하기 SYSDATE + 7 DATE_ADD(NOW(), INTERVAL 7 DAY) DATEADD(day, 7, GETDATE())
월 더하기 ADD_MONTHS(SYSDATE, 3) DATE_ADD(NOW(), INTERVAL 3 MONTH) DATEADD(month, 3, GETDATE())
년 더하기 ADD_MONTHS(SYSDATE, 12) DATE_ADD(NOW(), INTERVAL 1 YEAR) DATEADD(year, 1, GETDATE())
일 빼기 SYSDATE - 30 DATE_SUB(NOW(), INTERVAL 30 DAY) DATEADD(day, -30, GETDATE())

📝 실무 예제: 최근 30일간 주문 데이터 조회

Oracle

SELECT order_id, customer_id, order_date, total_amount FROM orders WHERE order_date >= SYSDATE - 30 AND order_date < SYSDATE + 1 ORDER BY order_date DESC; -- 월별 조회 (지난 3개월) SELECT order_id, customer_id, order_date FROM orders WHERE order_date >= ADD_MONTHS(SYSDATE, -3) ORDER BY order_date DESC;

MySQL

SELECT order_id, customer_id, order_date, total_amount FROM orders WHERE order_date >= DATE_SUB(NOW(), INTERVAL 30 DAY) AND order_date <= NOW() ORDER BY order_date DESC; -- 월별 조회 (지난 3개월) SELECT order_id, customer_id, order_date FROM orders WHERE order_date >= DATE_SUB(NOW(), INTERVAL 3 MONTH) ORDER BY order_date DESC;

MS SQL Server

SELECT order_id, customer_id, order_date, total_amount FROM orders WHERE order_date >= DATEADD(day, -30, GETDATE()) AND order_date <= GETDATE() ORDER BY order_date DESC; -- 월별 조회 (지난 3개월) SELECT order_id, customer_id, order_date FROM orders WHERE order_date >= DATEADD(month, -3, GETDATE()) ORDER BY order_date DESC;

📊 3. 날짜 차이 계산

두 날짜 간의 차이를 계산하는 방법도 각각 다릅니다.

차이 단위 Oracle MySQL MS SQL Server
일 차이 date2 - date1 DATEDIFF(date2, date1) DATEDIFF(day, date1, date2)
월 차이 MONTHS_BETWEEN(date2, date1) TIMESTAMPDIFF(MONTH, date1, date2) DATEDIFF(month, date1, date2)
년 차이 MONTHS_BETWEEN(date2, date1) / 12 TIMESTAMPDIFF(YEAR, date1, date2) DATEDIFF(year, date1, date2)
MySQL의 DATEDIFF는 일 차이만 계산하고, 시간/분/초 차이는 TIMESTAMPDIFF를 사용해야 합니다. 반면 MS SQL Server의 DATEDIFF는 다양한 단위를 지원합니다.

🎨 4. 날짜 포맷팅

날짜를 원하는 형식의 문자열로 변환하는 방법도 각각 완전히 다릅니다.

형식 Oracle MySQL MS SQL Server
YYYY-MM-DD TO_CHAR(date, 'YYYY-MM-DD') DATE_FORMAT(date, '%Y-%m-%d') FORMAT(date, 'yyyy-MM-dd')
DD/MM/YYYY TO_CHAR(date, 'DD/MM/YYYY') DATE_FORMAT(date, '%d/%m/%Y') FORMAT(date, 'dd/MM/yyyy')
한국어 형식 TO_CHAR(date, 'YYYY"년" MM"월" DD"일"') DATE_FORMAT(date, '%Y년 %m월 %d일') FORMAT(date, 'yyyy년 MM월 dd일')

Oracle 포맷팅

-- 다양한 형식 예제 SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') AS datetime_format, TO_CHAR(SYSDATE, 'YYYY"년" MM"월" DD"일"') AS korean_format, TO_CHAR(SYSDATE, 'Day, DD Month YYYY') AS english_format, TO_CHAR(SYSDATE, 'Q') AS quarter, TO_CHAR(SYSDATE, 'WW') AS week_of_year FROM dual;

MySQL 포맷팅

-- 다양한 형식 예제 SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS datetime_format, DATE_FORMAT(NOW(), '%Y년 %m월 %d일') AS korean_format, DATE_FORMAT(NOW(), '%W, %d %M %Y') AS english_format, QUARTER(NOW()) AS quarter, WEEK(NOW()) AS week_of_year;

MS SQL Server 포맷팅

-- 다양한 형식 예제 SELECT FORMAT(GETDATE(), 'yyyy-MM-dd HH:mm:ss') AS datetime_format, FORMAT(GETDATE(), 'yyyy년 MM월 dd일') AS korean_format, FORMAT(GETDATE(), 'dddd, dd MMMM yyyy', 'en-US') AS english_format, DATEPART(QUARTER, GETDATE()) AS quarter, DATEPART(WEEK, GETDATE()) AS week_of_year;

🔧 5. 날짜 추출 함수

날짜에서 년, 월, 일 등의 특정 부분을 추출하는 방법입니다.

추출 요소 Oracle MySQL MS SQL Server
년도 EXTRACT(YEAR FROM date) YEAR(date) YEAR(date)
EXTRACT(MONTH FROM date) MONTH(date) MONTH(date)
EXTRACT(DAY FROM date) DAY(date) DAY(date)
요일 TO_CHAR(date, 'D') DAYOFWEEK(date) DATEPART(WEEKDAY, date)
분기 TO_CHAR(date, 'Q') QUARTER(date) DATEPART(QUARTER, date)
요일 번호는 각 데이터베이스마다 다릅니다! Oracle과 MS SQL Server는 일요일이 1, MySQL은 일요일이 1이지만 설정에 따라 달라질 수 있습니다.

📅 6. 특별한 날짜 함수들

각 데이터베이스만의 독특한 날짜 관련 함수들을 살펴보겠습니다.

Oracle 특별 함수

-- LAST_DAY: 해당 월의 마지막 날 SELECT LAST_DAY(SYSDATE) FROM dual; -- 결과: 2025-01-31 -- NEXT_DAY: 다음 요일 찾기 SELECT NEXT_DAY(SYSDATE, '일요일') FROM dual; -- TRUNC: 날짜 자르기 SELECT TRUNC(SYSDATE, 'MONTH') FROM dual; -- 월 첫날 SELECT TRUNC(SYSDATE, 'YEAR') FROM dual; -- 년 첫날 -- ROUND: 날짜 반올림 SELECT ROUND(SYSDATE, 'MONTH') FROM dual; -- ADD_MONTHS: 월 더하기 (말일 처리 자동) SELECT ADD_MONTHS('2025-01-31', 1) FROM dual; -- 결과: 2025-02-28 (2월 말일로 자동 조정)

MySQL 특별 함수

-- LAST_DAY: 해당 월의 마지막 날 SELECT LAST_DAY(NOW()); -- 결과: 2025-01-31 -- DAYNAME: 요일명 반환 SELECT DAYNAME(NOW()); -- 결과: Wednesday -- WEEKDAY: 요일 번호 (월요일=0) SELECT WEEKDAY(NOW()); -- STR_TO_DATE: 문자열을 날짜로 변환 SELECT STR_TO_DATE('2025-01-15', '%Y-%m-%d'); -- MAKEDATE: 년도와 일수로 날짜 생성 SELECT MAKEDATE(2025, 100); -- 2025년의 100번째 날 -- PERIOD_DIFF: 기간 차이 (YYYYMM 형식) SELECT PERIOD_DIFF(202501, 202412); -- 결과: 1 (1개월 차이)

MS SQL Server 특별 함수

-- EOMONTH: 해당 월의 마지막 날 SELECT EOMONTH(GETDATE()); -- 결과: 2025-01-31 -- DATEFROMPARTS: 년,월,일로 날짜 생성 SELECT DATEFROMPARTS(2025, 12, 25); -- 결과: 2025-12-25 -- TIMEFROMPARTS: 시,분,초로 시간 생성 SELECT TIMEFROMPARTS(14, 30, 0, 0, 0); -- ISDATE: 유효한 날짜인지 확인 SELECT ISDATE('2025-02-29'); -- 결과: 0 (무효) SELECT ISDATE('2024-02-29'); -- 결과: 1 (유효, 윤년) -- SWITCHOFFSET: 시간대 변경 SELECT SWITCHOFFSET(SYSDATETIMEOFFSET(), '+09:00');

🔄 7. 실무 변환 예제

실제 업무에서 자주 사용되는 날짜 처리를 각 데이터베이스별로 구현해보겠습니다.

💼 예제 시나리오: 고객 가입 기간 및 생일 분석

고객의 나이, 가입 기간, 다음 생일까지의 일수를 계산하는 쿼리를 각 데이터베이스별로 작성해보겠습니다.

Oracle 버전

SELECT customer_id, customer_name, birth_date, register_date, -- 나이 계산 FLOOR(MONTHS_BETWEEN(SYSDATE, birth_date) / 12) AS age, -- 가입 기간 (일) FLOOR(SYSDATE - register_date) AS days_since_registration, -- 가입 기간 (월) FLOOR(MONTHS_BETWEEN(SYSDATE, register_date)) AS months_since_registration, -- 이번 년도 생일 ADD_MONTHS(birth_date, FLOOR(MONTHS_BETWEEN(SYSDATE, birth_date) / 12) * 12) AS this_year_birthday, -- 다음 생일까지 일수 CASE WHEN ADD_MONTHS(birth_date, FLOOR(MONTHS_BETWEEN(SYSDATE, birth_date) / 12) * 12) >= TRUNC(SYSDATE) THEN ADD_MONTHS(birth_date, FLOOR(MONTHS_BETWEEN(SYSDATE, birth_date) / 12) * 12) - TRUNC(SYSDATE) ELSE ADD_MONTHS(birth_date, FLOOR(MONTHS_BETWEEN(SYSDATE, birth_date) / 12) * 12 + 12) - TRUNC(SYSDATE) END AS days_to_birthday, -- 분기별 가입 정보 'Q' || TO_CHAR(register_date, 'Q') || ' ' || TO_CHAR(register_date, 'YYYY') AS register_quarter FROM customers;

MySQL 버전

SELECT customer_id, customer_name, birth_date, register_date, -- 나이 계산 TIMESTAMPDIFF(YEAR, birth_date, NOW()) AS age, -- 가입 기간 (일) DATEDIFF(NOW(), register_date) AS days_since_registration, -- 가입 기간 (월) TIMESTAMPDIFF(MONTH, register_date, NOW()) AS months_since_registration, -- 이번 년도 생일 DATE(CONCAT(YEAR(NOW()), '-', LPAD(MONTH(birth_date), 2, '0'), '-', LPAD(DAY(birth_date), 2, '0'))) AS this_year_birthday, -- 다음 생일까지 일수 CASE WHEN DATE(CONCAT(YEAR(NOW()), '-', LPAD(MONTH(birth_date), 2, '0'), '-', LPAD(DAY(birth_date), 2, '0'))) >= CURDATE() THEN DATEDIFF( DATE(CONCAT(YEAR(NOW()), '-', LPAD(MONTH(birth_date), 2, '0'), '-', LPAD(DAY(birth_date), 2, '0'))), CURDATE()) ELSE DATEDIFF( DATE(CONCAT(YEAR(NOW()) + 1, '-', LPAD(MONTH(birth_date), 2, '0'), '-', LPAD(DAY(birth_date), 2, '0'))), CURDATE()) END AS days_to_birthday, -- 분기별 가입 정보 CONCAT('Q', QUARTER(register_date), ' ', YEAR(register_date)) AS register_quarter FROM customers;

MS SQL Server 버전

SELECT customer_id, customer_name, birth_date, register_date, -- 나이 계산 DATEDIFF(year, birth_date, GETDATE()) - CASE WHEN DATEADD(year, DATEDIFF(year, birth_date, GETDATE()), birth_date) > GETDATE() THEN 1 ELSE 0 END AS age, -- 가입 기간 (일) DATEDIFF(day, register_date, GETDATE()) AS days_since_registration, -- 가입 기간 (월) DATEDIFF(month, register_date, GETDATE()) AS months_since_registration, -- 이번 년도 생일 DATEFROMPARTS(YEAR(GETDATE()), MONTH(birth_date), DAY(birth_date)) AS this_year_birthday, -- 다음 생일까지 일수 CASE WHEN DATEFROMPARTS(YEAR(GETDATE()), MONTH(birth_date), DAY(birth_date)) >= CAST(GETDATE() AS DATE) THEN DATEDIFF(day, CAST(GETDATE() AS DATE), DATEFROMPARTS(YEAR(GETDATE()), MONTH(birth_date), DAY(birth_date))) ELSE DATEDIFF(day, CAST(GETDATE() AS DATE), DATEFROMPARTS(YEAR(GETDATE()) + 1, MONTH(birth_date), DAY(birth_date))) END AS days_to_birthday, -- 분기별 가입 정보 'Q' + CAST(DATEPART(QUARTER, register_date) AS VARCHAR) + ' ' + CAST(YEAR(register_date) AS VARCHAR) AS register_quarter FROM customers;

⚡ 8. 성능 고려사항

날짜 함수 사용 시 성능을 고려해야 할 중요한 포인트들입니다.

🚀 인덱스 활용 팁

-- ❌ 나쁜 예: 함수를 인덱스된 열에 사용 SELECT * FROM orders WHERE YEAR(order_date) = 2025; -- ✅ 좋은 예: 범위 조건 사용 SELECT * FROM orders WHERE order_date >= '2025-01-01' AND order_date < '2026-01-01';

📊 대용량 데이터 처리

-- 파티셔닝을 고려한 날짜 조건 SELECT * FROM large_table WHERE date_column >= DATEADD(month, -1, GETDATE()) AND date_column < GETDATE(); -- 적절한 날짜 인덱스 생성 CREATE INDEX IX_orders_date ON orders(order_date) INCLUDE (customer_id, total_amount);

🔧 최적화 기법

  • 날짜 리터럴 사용: 문자열보다 날짜 리터럴 사용
  • 함수 인덱스: 자주 사용하는 날짜 함수에 대해 함수 기반 인덱스 생성
  • 파티셔닝: 대용량 테이블의 날짜 기반 파티셔닝
  • 계산된 열: 복잡한 날짜 계산은 계산된 열로 저장

🎯 9. 마이그레이션 가이드

데이터베이스 간 마이그레이션 시 날짜 함수 변환을 위한 실용적인 가이드입니다.

마이그레이션 방향 주요 변경사항 주의사항
Oracle → MySQL • SYSDATE → NOW()
• TO_CHAR → DATE_FORMAT
• ADD_MONTHS → DATE_ADD
• TRUNC → DATE 함수
• Oracle의 날짜 연산(+/-) 불가
• 포맷 문자열 완전히 다름
• DUAL 테이블 불필요
Oracle → MS SQL • SYSDATE → GETDATE()
• TO_CHAR → FORMAT
• ADD_MONTHS → DATEADD
• MONTHS_BETWEEN → DATEDIFF
• 날짜 연산 방식 완전 변경
• FROM dual 제거 필요
• 데이터 타입 매핑 주의
MySQL → MS SQL • NOW() → GETDATE()
• DATE_FORMAT → FORMAT
• DATE_ADD → DATEADD
• CURDATE() → CAST(GETDATE() AS DATE)
• LIMIT → TOP 변환
• 백틱(`) → 대괄호[] 변환
• 자동 형변환 차이

🛠️ 마이그레이션 도구 추천

  • AWS SCT (Schema Conversion Tool): 다양한 DB 간 스키마 변환
  • Microsoft SSMA: Oracle/MySQL → SQL Server 마이그레이션
  • DBConvert: 상용 마이그레이션 도구
  • 정규식 기반 스크립트: 단순 함수 변환용

📚 10. 실무 베스트 프랙티스

✅ 권장사항

  • 표준 SQL 우선 사용: CURRENT_TIMESTAMP, EXTRACT 등
  • 명시적 형변환: 암시적 변환에 의존하지 말 것
  • 타임존 고려: 글로벌 서비스 시 UTC 기준 사용
  • 일관된 형식: 프로젝트 내 날짜 형식 통일
  • NULL 처리: 날짜 계산 시 NULL 값 고려

❌ 피해야 할 것들

  • 문자열 날짜 연산: '2025-01-01' + 1 같은 연산
  • 하드코딩된 형식: 지역별 설정에 의존하는 형식
  • 복잡한 중첩 함수: 가독성과 성능 저하
  • 인덱스 컬럼 함수 적용: WHERE YEAR(date) = 2025
  • 윤년 무시: 2월 29일 처리 주의

🔍 테스트 체크리스트

  • 윤년 처리: 2월 29일 관련 로직
  • 월말 처리: 31일 → 30일 변환
  • 타임존 변환: 서머타임 적용
  • NULL 값 처리: 날짜가 NULL인 경우
  • 경계값 테스트: 년도 변경, 월 변경 시점
반응형