공공부하자개발 · 영어 학습 노트
SQL
SQL 중급서브쿼리·조인·함수·DDL·인덱스0/11 완료
  • 01서브쿼리: 스칼라·인라인 뷰·상관 서브쿼리, DB별 차이
  • 02EXISTS·IN·NOT IN 과 NULL 함정
  • 03조인 심화: INNER·OUTER·SELF·CROSS, Oracle (+)
  • 04집합 연산: UNION·UNION ALL·INTERSECT·MINUS/EXCEPT
  • 05조건 로직: CASE·DECODE·IIF
  • 06NULL 처리 함수
  • 07문자·날짜 함수 DB별 비교
  • 08DDL 과 제약 조건
  • 09인덱스 기초
  • 10집계와 GROUP BY·HAVING
  • 11뷰·시퀀스·자동 증가
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › SQL 중급 › 07 / 11

문자·날짜 함수 DB별 비교

섹션 6진행 0 / 11
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6정리‹ 이전다음 ›

4. 응용 변형 예제

소스: sql-src/mid_07_string_date/02_date.sql, 03_dialects.sql. 날짜 계산과 DB별 함수 이름 차이를 확인합니다.

변형 1: 날짜 더하기와 월말 처리

sql
SELECT
       DATE '2024-01-15' + 10                AS plus_10_day
     , DATEADD('MONTH', 1, DATE '2024-01-15') AS mid_month
     , DATEADD('MONTH', 1, DATE '2024-01-31') AS from_month_end
  FROM orders
 WHERE id = 1;
text
PLUS_10_DAY | MID_MONTH  | FROM_MONTH_END
------------+------------+---------------
2024-01-25  | 2024-02-15 | 2024-02-29
(1행)

날짜 + 숫자 는 그 일수만큼 뒤 날짜이고, DATEADD('MONTH', n, 날짜) 는 개월 단위로 더합니다. 1월 15일에 1개월을 더하면 2월 15일로 같은 일자로 옮겨가지만, 1월 31일에 1개월을 더하면 2월에는 31일이 없어 2월 말일(2024-02-29, 윤년)로 자동 조정됩니다.

1월 31일처럼 옮겨 갈 날이 없으면 말일로 맞추는 규칙은 Oracle ADD_MONTHS, MySQL DATE_ADD, MSSQL DATEADD 가 같습니다.

원래 날짜가 말일이면 다릅니다. 실제 Oracle 은 2024-02-29 + 1개월을 3월 말일(2024-03-31)로 맞추고, MySQL·MSSQL 은 같은 일자인 2024-03-29 를 돌려줍니다. H2 는 Oracle 모드에서도 2024-03-29 를 돌려줘 이 차이는 재현되지 않으며 문법 검토만 했습니다. 월말 정산처럼 "매달 말일"이 필요하면 개월을 더한 뒤 LAST_DAY 를 한 번 더 씌우는 것이 안전합니다.

변형 2: 월초·월말 구하기와 날짜 차이

sql
SELECT
       DATE_TRUNC('MONTH', ord_ts)                             AS month_start
     , LAST_DAY(ord_ts)                                        AS month_end
     , DATEDIFF('DAY', DATE '2024-01-01', DATE '2024-03-01')   AS day_diff
     , DATEDIFF('MONTH', DATE '2024-01-01', DATE '2024-03-01') AS month_diff
  FROM orders
 WHERE id = 3;
text
MONTH_START           | MONTH_END  | DAY_DIFF | MONTH_DIFF
----------------------+------------+----------+-----------
2024-02-01 00:00:00.0 | 2024-02-29 | 60       | 2
(1행)

DATE_TRUNC('MONTH', ...) 는 그달 1일 0시로, LAST_DAY 는 그달의 마지막 날짜로 잘라냅니다. Oracle 은 TRUNC(d, 'MM') 로 월초를 구하지만 H2 는 이 2인자 형태를 지원하지 않아 DATE_TRUNC 로 대신합니다.

DATEDIFF('DAY', ...)·DATEDIFF('MONTH', ...) 는 두 날짜의 일수·개월 수 차이이며, Oracle 의 MONTHS_BETWEEN 은 일수까지 반영한 소수를 주는 점만 다릅니다.

변형 3: 날짜 ↔ 문자 변환

sql
SELECT
       FORMATDATETIME(ord_ts, 'yyyy-MM-dd')             AS date_to_str
     , CAST(PARSEDATETIME('2024-01-31', 'yyyy-MM-dd')
            AS DATE)                                    AS str_to_date
  FROM orders
 WHERE id = 1;
text
DATE_TO_STR | STR_TO_DATE
------------+------------
2024-01-31  | 2024-01-31
(1행)

FORMATDATETIME 은 날짜를 지정한 형식의 문자열로, PARSEDATETIME 은 문자열을 날짜로 바꿉니다. Oracle 의 TO_CHAR·TO_DATE 와 역할이 같지만 형식 문자(yyyy-MM-dd)는 Oracle 의 YYYY-MM-DD 와 대소문자 표기가 다릅니다.

변형 4: 날짜 범위 조건의 경계 함정

sql
SELECT
       id
     , cust
     , ord_ts
  FROM orders
 WHERE ord_ts BETWEEN DATE '2024-02-01' AND DATE '2024-02-15'
 ORDER BY id;
text
ID | CUST   | ORD_TS
---+--------+----------------------
2  | 이서연 | 2024-02-01 23:59:00.0
(1행)

2월 15일 낮 12시에 주문한 박도윤(id 3)이 빠졌습니다. DATE '2024-02-15' 가 "2월 15일 0시"로 해석되어, 그보다 늦은 시각의 주문은 범위 밖으로 밀려났기 때문입니다.

sql
SELECT
       id
     , cust
     , ord_ts
  FROM orders
 WHERE ord_ts >= DATE '2024-02-01'
   AND ord_ts <  DATE '2024-02-16'
 ORDER BY id;
text
ID | CUST   | ORD_TS
---+--------+----------------------
2  | 이서연 | 2024-02-01 23:59:00.0
3  | 박도윤 | 2024-02-15 12:00:00.0
(2행)

종료 조건을 < 2024-02-16(다음 날)으로 바꾸면 2월 15일 안의 모든 시각이 포함되어 박도윤의 주문도 잡힙니다. 이 패턴은 시간 성분이 있는 날짜 컬럼이라면 DB를 가리지 않고 항상 안전합니다.

변형 5: Oracle·Tibero — 미지원 함수와 대안

LENGTHB 는 3절 예제1 의 OCTET_LENGTH 로, TRUNC(날짜,'MM') 은 4절 변형2 의 DATE_TRUNC 로 이미 대안을 확인했습니다. 여기서는 INITCAP·MONTHS_BETWEEN 을 봅니다.

sql
-- Oracle · Tibero
SET MODE Oracle;
-- @error
SELECT INITCAP('hello world') FROM emp WHERE id = 1;

SELECT
       CONCAT(UPPER(SUBSTR('hello world', 1, 1)),
              LOWER(SUBSTR('hello world', 2))) AS initcap_alt
  FROM emp
 WHERE id = 1;

-- @error
SELECT MONTHS_BETWEEN(hired, DATE '2024-01-01') FROM emp WHERE id = 1;
text
예상 오류: Function "INITCAP" not found
text
INITCAP_ALT
-----------
Hello world
(1행)
text
예상 오류: Function "MONTHS_BETWEEN" not found

단어 첫 글자만 대문자로 바꾸는 INITCAP 은 H2 에 없습니다(H2 미지원, 문법 검토만). 첫 글자만 SUBSTR+UPPER, 나머지는 SUBSTR+LOWER 로 떼어 이어 붙이면 같은 결과를 만들 수 있습니다. MONTHS_BETWEEN 도 H2 미지원이며, 4절 변형2 에서 실행한 DATEDIFF('MONTH', ...) 가 정수 단위 대안입니다(실제 Oracle 은 일수까지 반영한 소수를 줍니다).

변형 6: MySQL — 관대함과 미지원 함수

sql
-- MySQL
SET MODE MySQL;
SELECT
       LENGTH(name)       AS length_result
     , CHAR_LENGTH(name)   AS char_len
  FROM emp
 WHERE id = 1;

SELECT
       CONCAT('김', NULL) AS concat_with_null
  FROM emp
 WHERE id = 1;

-- @error
SELECT DATE_ADD(hired, INTERVAL 1 MONTH) FROM emp WHERE id = 1;

SELECT
       hired + INTERVAL '1' MONTH AS date_add_alt
  FROM emp
 WHERE id = 1;
text
LENGTH_RESULT | CHAR_LEN
--------------+---------
3             | 3
(1행)
text
CONCAT_WITH_NULL
----------------
김
(1행)
text
예상 오류: Function "DATE_ADD" not found
text
DATE_ADD_ALT
------------
2024-02-29
(1행)

실제 MySQL 의 LENGTH 는 바이트 수(9)를 주지만 H2 는 문자 수(3)를 주고, 실제 MySQL 의 CONCAT 은 NULL 이 섞이면 결과가 NULL 이지만 H2 는 NULL 을 빼고 이어 붙입니다. 둘 다 H2 에서 재현 안 됨(문법 검토만)입니다.

DATE_ADD 함수명도 H2 미지원이지만(문법 검토만), 날짜 + INTERVAL '값' 단위 표준 구문은 그대로 동작하고 월말 자동 조정도 같습니다. DATEDIFF(a, b) 2인자 형태와 DATE_FORMAT·STR_TO_DATE 도 같은 이유로 H2 미지원이며, 대안은 각각 4절 변형2 의 DATEDIFF('DAY', ...), 변형3 의 FORMATDATETIME·PARSEDATETIME 과 같습니다.

변형 7: MSSQL — 관대함과 미지원 함수

sql
-- MSSQL
SET MODE MSSQLServer;
-- @error
SELECT REPLICATE('0', 3) FROM emp WHERE id = 1;

SELECT
       LPAD(CAST(sal AS VARCHAR(10)), 6, '0') AS zero_pad_alt
  FROM emp
 WHERE id = 1;

-- @error
SELECT CONVERT(VARCHAR(10), hired, 23) FROM emp WHERE id = 1;

SELECT
       CONVERT(VARCHAR(10), hired) AS convert_alt
  FROM emp
 WHERE id = 1;
text
예상 오류: Function "REPLICATE" not found
text
ZERO_PAD_ALT
------------
000900
(1행)
text
예상 오류: Syntax error in SQL statement "SELECT CONVERT(VARCHAR(10), hired[*], 23) FROM emp WHERE id = 1"; expected "(, ., [, ., ::, AT, FORMAT, *, /, %, +, -, ||, NOT, IS, ILIKE, REGEXP, AND, OR, )"
text
CONVERT_ALT
-----------
2024-01-31
(1행)

REPLICATE·DATALENGTH·EOMONTH 는 모두 H2 미지원입니다(문법 검토만). DATALENGTH 대안은 3절 예제1 의 OCTET_LENGTH(9)와 같고, EOMONTH 대안은 4절 변형2 의 LAST_DAY 와 같습니다.

MSSQL 의 CONVERT(타입, 값, 스타일번호) 는 스타일 23 이 YYYY-MM-DD 형식인데, H2 는 스타일 번호를 지원하지 않고(문법 검토만) 항상 ISO 형식만 줍니다. FORMAT(hired, 'yyyy-MM-dd') 도 H2 미지원이라 같은 방식으로 확인됩니다.

주의

H2 는 모드와 무관하게 LPAD·RPAD·LAST_DAY 를 전역으로 지원하고 CONVERT 는 스타일 번호 없이도 실행되지만, 실제 MSSQL 에는 LPAD·RPAD·LAST_DAY 가 없고 CONVERT 는 스타일 번호가 없으면 Jan 31 2024 같은 영문 형식이 나옵니다(H2 에서 재현 안 됨, 문법 검토만). 실제 코드에서는 RIGHT(REPLICATE('0', n) + 값, n)·EOMONTH·CONVERT(..., 23) 을 각각 써야 합니다.

응용 변형 예제
  • 변형 1: 날짜 더하기와 월말 처리
  • 변형 2: 월초·월말 구하기와 날짜 차이
  • 변형 3: 날짜 ↔ 문자 변환
  • 변형 4: 날짜 범위 조건의 경계 함정
  • 변형 5: Oracle·Tibero — 미지원 함수와 대안
  • 변형 6: MySQL — 관대함과 미지원 함수
  • 변형 7: MSSQL — 관대함과 미지원 함수
이전 섹션3 코드 예제4 / 6다음 섹션5 자주 하는 실수 (Tip)