문자·숫자·날짜·변환·NULL 함수와 CASE·DECODE를 익히고, 날짜 범위 조건과 형 변환 함정까지 기출 기준으로 정리합니다.
최빈출기출 11회분 중 72문항 · 많이 나온 주제: NVL/NVL2(22), COALESCE(13), 날짜/형변환(11)
학습 목표
문자·숫자·날짜·변환·NULL 함수와 CASE·DECODE를 익히고, 날짜 범위 조건과 형 변환 함정까지 기출 기준으로 정리합니다.
01
함수 한눈에 보기: 단일행 vs 집계
함수는 값을 받아 정해진 계산을 하고 결과를 돌려줍니다. 먼저 행마다 계산하는지(단일행), 여러 행을 하나로 요약하는지(집계)를 구분합니다.
같은 4행 데이터에 함수를 쓰면같은 입력에서 결과 행 수가 어떻게 달라지는지 보세요.
단일행 함수4행 →입력, 결과4행
UPPER(NICKNAME)
입력 4행
NICKNAME
mina
JUNO
sora
DAVID
행마다 계산
결과 4행
UPPER 결과
MINA
JUNO
SORA
DAVID
각 닉네임을 대문자로 바꾸고 4행을 유지합니다.
집계 함수4행 →입력, 결과1행
COUNT(*)
입력 4행
NICKNAME
mina
JUNO
sora
DAVID
전체를 요약
결과 1행
COUNT(*)
4
입력 4건을 세어 숫자 4 하나를 반환합니다.
이 예시는 필터·DISTINCT·GROUP BY 없이 비교합니다. GROUP BY가 있으면 그룹마다 집계 결과가 나옵니다.
함수 분류와 대표 함수
분류
하는 일
대표 함수
문자
대소문자·추출·검색·치환
UPPERLOWERSUBSTRINSTRLENGTHREPLACE
숫자
반올림·절삭·나머지
ROUNDTRUNCMODABSCEILFLOOR
날짜
월 이동·날짜 차이·월말
SYSDATEADD_MONTHSMONTHS_BETWEENLAST_DAY
변환
문자·숫자·날짜 자료형 바꾸기
TO_CHARTO_NUMBERTO_DATE
NULL·조건
NULL 대체·조건 분기
NVLNVL2NULLIFCOALESCEDECODECASE
집계(다중행)
여러 행을 요약
COUNTSUMAVGMAXMIN
집계 함수는 GROUP BY 단원에서 자세히 다룹니다. CASE는 엄밀히는 함수가 아니라 조건 표현식이지만, 시험에서는 DECODE와 함께 비교해서 공부합니다.
02
문자 함수
문자 함수는 대소문자 변환, 길이 확인, 일부 문자열 추출·치환·공백 제거에 사용합니다. LOWER·UPPER·LENGTH·SUBSTR·REPLACE·TRIM이 대표적입니다.
문자 위치는 1부터 셉니다. SUBSTR(문자, 시작, 길이)의 세 번째 인자는 끝 위치가 아니라 길이이고, INSTR는 찾은 위치(숫자)를 돌려줍니다. LTRIM은 왼쪽, RTRIM은 오른쪽, TRIM은 양쪽 끝을 다듬고, REPLACE는 문자열 안쪽까지 바꿉니다.
대표 문자 함수
함수
의미
예시 → 결과
UPPER / LOWER
대문자 / 소문자
UPPER('sqld') → SQLD
INITCAP
단어 첫 글자만 대문자
INITCAP('hi sql') → Hi Sql
LENGTH
문자 수 (공백 포함)
LENGTH('한글') → 2
SUBSTR
시작 위치부터 길이만큼 추출
SUBSTR('ABCDE',2,3) → BCD
INSTR
찾은 위치
INSTR('ABCDE','C') → 3
LPAD / RPAD
지정 길이까지 왼쪽 / 오른쪽 채우기
LPAD('7',3,'0') → 007
LTRIM / RTRIM
왼쪽 / 오른쪽 끝 문자 제거
LTRIM('xxSQLxx','x') → SQLxx
TRIM
양쪽 끝 문자 제거
TRIM('x' FROM 'xxSQLxx') → SQL
REPLACE
일치하는 부분 전부 바꾸기
REPLACE('A-B','-','+') → A+B
CONCAT / ||
문자열 이어 붙이기
CONCAT('SQL','D') → SQLD
-- 길이·위치의 인자 의미를 먼저 확인SELECTSUBSTR('ABCDE',2,3)AS CUT_TEXT,INSTR('ABCDE','C')AS FOUND_AT,LTRIM('xxSQLxx','x')AS LEFT_TRIMMED,TRIM(BOTH 'x'FROM'xxSQLxx')AS BOTH_TRIMMED
FROMDUAL;-- 결과: BCD | 3 | SQLxx | SQL
TRIM은 TRIM('지울 문자' FROM 문자열)형식입니다. LTRIM·RTRIM처럼 쉼표로 TRIM(문자열, '지울 문자')라고 쓰면 Oracle에서 문법 오류입니다. 지울 문자를 생략한 TRIM(문자열)은 양쪽 공백을 지웁니다. REPLACE에서 바꿀 문자(세 번째 인자)를 생략하면 찾은 문자를 삭제합니다.
TRIM 계열과 REPLACE 결과 비교
식
결과
이유
TRIM('#' FROM '##SQL##')
SQL
양쪽 끝의 # 제거
TRIM('##SQL##', '#')
오류
TRIM에는 쉼표 2인자 형식이 없음
LTRIM('##SQL', '#')
SQL
왼쪽 끝의 # 제거
RTRIM('SQL##', '#')
SQL
오른쪽 끝의 # 제거
REPLACE('##SQL##', '#')
SQL
바꿀 문자 생략 → 삭제
REPLACE('A-B-C', '-', '+')
A+B+C
가운데까지 모두 바꿈
03
숫자 함수
숫자 함수는 절댓값·반올림·절삭·나머지 등을 계산합니다. ABS·ROUND·TRUNC·CEIL·FLOOR·MOD의 입력과 반환값을 작은 예제로 확인합니다.
가장 중요한 구분은 ROUND(반올림)와 TRUNC(버림)입니다. 두 번째 인자 m은 남길 자리입니다. 1은 소수 첫째 자리, 0은 정수, -2는 백의 자리까지 남깁니다. CEIL은 그 값 이상인 가장 작은 정수, FLOOR는 그 값 이하인 가장 큰 정수라서 음수에서 헷갈리기 쉽습니다.
ROUND(값, n)에서 n이 양수면 소수점 아래 n자리, 0이거나 생략하면 정수, 음수면 정수부에서 반올림합니다. 반올림은 바로 다음 자리 숫자 하나만 보고 정합니다.
ROUND와 TRUNC 자리 수 연습
식
결과
판단
ROUND(254.7, -1)
250
일의 자리 4 → 버림
ROUND(255, -1)
260
일의 자리 5 → 올림
ROUND(6.5, 0) / ROUND(6.5)
7 / 7
n 생략 = 0
ROUND(-4.786, 2)
-4.79
소수 셋째 자리 6 → 올림
TRUNC(-4.786, 2)
-4.78
자리 아래는 그냥 버림
04
날짜와 변환 함수
날짜 함수는 날짜 연산과 일부 날짜 요소 추출을 수행합니다. Oracle의 SYSDATE·ADD_MONTHS·MONTHS_BETWEEN·EXTRACT 등은 DBMS별 함수와 반환 규칙이 다를 수 있습니다.
TO_CHAR·TO_NUMBER·TO_DATE 같은 변환 함수는 형식을 명시해 자료형 사이를 변환합니다. 암시적 변환은 NLS 설정이나 데이터에 따라 오류·비교 결과 차이를 만들 수 있습니다.
Oracle DATE에는 시·분·초까지 들어 있습니다. DATE - DATE는 일수(숫자), DATE + 숫자는 며칠 뒤 날짜입니다. 1을 더하면 1시간이 아니라 1일이 늘어납니다.
날짜·변환 함수
함수·연산
하는 일
예시 → 결과
ADD_MONTHS(d, n)
n개월 이동
2026-04-26, 1 → 2026-05-26
MONTHS_BETWEEN(d1, d2)
개월 차이(숫자)
04-26과 03-26 → 1
LAST_DAY(d)
그 달의 마지막 날
2026-04-26 → 2026-04-30
EXTRACT(YEAR FROM d)
연도만 꺼내기
→ 2026
EXTRACT(MONTH FROM d)
월만 꺼내기(숫자)
→ 4
TO_CHAR(d, 'MM')
월을 두 자리 문자로
→ '04'
TRUNC(d, 'MM')
그 달 1일(월초)
→ 2026-04-01
DATE - DATE
날짜 사이 일수
04-26 - 04-21 → 5
TO_CHAR(d, 'YYYY-MM-DD')
날짜 → 문자
2026-04-26
TO_CHAR(n, 'FM9,999')
숫자 → 형식 있는 문자
1234 → 1,234
TO_NUMBER('1234')
문자 → 숫자
1234
TO_DATE('20260426', 'YYYYMMDD')
문자 → 날짜
2026-04-26 DATE 값
월을 구하는 방법은 EXTRACT(MONTH FROM d)(숫자 4)와 TO_CHAR(d, 'MM')(문자 '04')입니다. EXTRACT(YEAR FROM d)는 연도라서 월이 나오지 않습니다.
-- 모든 결과가 실행 날짜와 무관한 고정 예제SELECTTO_CHAR(DATE'2026-04-26','YYYY-MM-DD')AS DATE_TEXT,EXTRACT(YEAR FROMDATE'2026-04-26')AS YEAR_NUM,MONTHS_BETWEEN(DATE'2026-04-26',DATE'2026-03-26')AS MONTH_GAP,TO_CHAR(TRUNC(DATE'2026-04-26','MM'),'YYYY-MM-DD')AS MONTH_START,DATE'2026-04-26'-DATE'2026-04-21'AS DAY_GAP
FROMDUAL;SELECTTO_CHAR(TO_DATE('20260426','YYYYMMDD'),'YYYY-MM-DD')AS DATE_TEXT,TO_NUMBER('1234')+1AS NUM_RESULT,TO_CHAR(1234,'FM9,999')AS FORMAT_NUM
FROMDUAL;-- 결과: 2026-04-26 | 2026 | 1 | 2026-04-01 | 5-- 2026-04-26 | 1235 | 1,234
05
날짜 범위 조건과 형 변환 함정
DATE 열에는 시·분·초가 함께 저장됩니다. DATE '2026-03-14'나 TO_DATE('20260314', 'YYYYMMDD')는 하루 전체가 아니라 그날 0시 0분 0초 한 순간입니다. 그래서 BETWEEN 14일 AND 15일로 하루를 조회하면 양 끝을 포함하므로 15일 0시 정각 행까지 걸립니다. 하루 전체는 >= 14일 AND < 15일처럼 다음 날 미만으로 씁니다.
일부 형식만 준 TO_DATE('2026-03', 'YYYY-MM')은 3월 1일 0시입니다. 그래서 TRUNC(일시) = TO_DATE('2026-03', 'YYYY-MM')는 3월 전체가 아니라 3월 1일 하루만 찾습니다. 한 달 전체는 TO_CHAR(일시, 'YYYYMM') = '202603'이나 >= 3월 1일 AND < 4월 1일로 씁니다.
TABLEORDERS 예시 — 주문 일시 4건4행
ORDER_ID
ORDER_AT
1
2026-03-14 09:30
2
2026-03-14 23:10
3
2026-03-15 00:00
4
2026-03-15 08:00
BETWEEN으로 14일 하루를 찾으면
ORDERS 4행
ORDER_ID
ORDER_AT
1
2026-03-14 09:30
2
2026-03-14 23:10
3
2026-03-15 00:00
4
2026-03-15 08:00
BETWEEN 14일 AND 15일→양 끝 포함
결과 3행 — 15일 0시까지 걸림
ORDER_ID
ORDER_AT
1
2026-03-14 09:30
2
2026-03-14 23:10
3
2026-03-15 00:00
DATE '2026-03-15'는 15일 0시 정각이라 주문 3이 끼어듭니다.
하루·한 달 조건별로 걸리는 주문
조건
걸리는 주문
판정
ORDER_AT BETWEEN DATE '2026-03-14' AND DATE '2026-03-15'
1, 2, 3
X — 15일 0시 포함
ORDER_AT >= DATE '2026-03-14' AND ORDER_AT < DATE '2026-03-15'
1, 2
O
TRUNC(ORDER_AT) = DATE '2026-03-14'
1, 2
O — 시각을 잘라 비교
TO_CHAR(ORDER_AT, 'YYYYMMDD') = '20260314'
1, 2
O
TRUNC(ORDER_AT) = TO_DATE('2026-03', 'YYYY-MM')
없음
X — 3월 1일과만 비교
TO_CHAR(ORDER_AT, 'YYYYMM') = '202603'
1, 2, 3, 4
O — 3월 전체
형 변환에서도 함정이 나옵니다. 숫자를 TO_CHAR로 바꾸면 문자 규칙으로 비교해 첫 글자부터 봅니다. 반대로 문자 '8'에 숫자를 더하면 Oracle이 숫자로 암시적 변환해 계산합니다. 하지만 숫자 20260314를 DATE 열에 그대로 넣으면 날짜로 바뀌지 않아 오류가 납니다.
B = 300, 50, 8일 때 형 변환 결과
식
결과
이유
MAX(B)
300
숫자 비교
MAX(TO_CHAR(B))
'8'
문자는 첫 글자 8이 가장 큼
MIN(TO_CHAR(B))
'300'
첫 글자 3이 가장 작음
'8' + 2
10
문자 → 숫자 암시적 변환
DATE 열에 숫자 20260314 INSERT
오류
숫자 → 날짜 자동 변환 없음
06
NULL 함수와 CASE
NVL·NVL2·COALESCE·NULLIF는 NULL 대체와 비교에 사용합니다. COALESCE는 왼쪽부터 NULL이 아닌 첫 값을 반환하고, NULLIF는 두 값이 같으면 NULL을 반환합니다.
CASE는 조건에 따라 값을 분기합니다. 단순 CASE는 기준 표현식과 값을 비교하고, searched CASE는 조건식을 순서대로 평가합니다.
박의 보너스 0은 NULL이 아니므로 NVL2는 0 + 100 = 100, COALESCE는 0을 그대로 돌려줍니다. NULLIF(0, 0)은 같은 값이라 NULL입니다.
NULL은 0도 빈칸도 아닌 값의 부재입니다. NULL이 낀 계산은 결과도 NULL이라, FEE - COUPON_DISCOUNT는 할인액이 NULL이면 NULL이 됩니다. NVL(COUPON_DISCOUNT, 0)으로 바꿔 계산할 수 있지만 저장된 값이 0으로 바뀌지는 않습니다.
NULL·조건 함수 규칙
함수
규칙
예시 → 결과
NVL(A, B)
A가 NULL이면 B
NVL(NULL, 0) → 0
NVL2(A, B, C)
A가 NULL 아니면 B, NULL이면 C
NVL2(NULL, '입력', '미입력') → 미입력
NULLIF(A, B)
A = B면 NULL, 아니면 A
NULLIF(5, 5) → NULL
COALESCE(A, B, ...)
왼쪽부터 첫 번째 NULL 아닌 값
COALESCE(NULL, NULL, '없음') → 없음
CASE WHEN ... END
조건(범위 포함)에 따라 결과 선택
FEE ≥ 45000 → 고액
DECODE(A, 값1, 결과1, ..., 기본값)
값이 같은지만 비교 (Oracle)
'사진' → PHOTO
-- 서로 다른 NULL 함수의 결과를 DUAL에서 확인SELECTNVL(NULL,0)AS NVL_RESULT,NVL2(NULL,'입력','미입력')AS NVL2_RESULT,NULLIF(5,5)AS NULLIF_RESULT,COALESCE(NULL,NULL,'없음')AS COALESCE_RESULT
FROMDUAL;-- 결과: 0 | 미입력 | NULL | 없음
SELECT NAME, SAL,CASEWHEN SAL >=5000THEN'상'WHEN SAL >=3000THEN'중'ELSE'하'ENDAS GRADE
FROM EMP;
CASE 조건은 위에서부터 검사하므로 순서가 결과에 영향을 줍니다.
조건에 맞는 것이 없을 때 CASE는 ELSE를, DECODE는 마지막 기본값을 돌려줍니다. 둘 다 생략하면 NULL입니다. 0이나 빈 문자열이 아닙니다.
일치하는 값이 없을 때
식
결과
이유
CASE 'K' WHEN 'M' THEN 1 END
NULL
ELSE 생략
DECODE('K', 'M', 1)
NULL
기본값 생략
DECODE('K', 'M', 1, 0)
0
기본값 0
NULLIF(3, 3)
NULL
두 값이 같음
COALESCE(NULL, 'K')
'K'
첫 비NULL 값
NULL을 다른 값으로 바꿀 때 COALESCE는 표준 SQL이라 DBMS와 상관없이 씁니다. NVL·NVL2·DECODE는 Oracle 함수입니다(참고: SQL Server는 ISNULL, MySQL은 IFNULL). NVL은 값을 바꿔 줄 뿐 더하지 않습니다.
보충 실습여기부터는 테이블을 직접 만들어 보는 긴 SQL 실습입니다. 처음 공부할 때는 건너뛰고, 위 내용을 이해한 뒤 돌아와도 됩니다.
07
종합 실습: 워크숍 신청 데이터로 함수 적용 전후 비교
보충 실습
워크숍 신청 4건으로 앞의 함수를 한 번에 연습합니다. 할인액 COUPON_DISCOUNT가 NULL인 행(101·104)은 할인액을 입력하지 않은 상태이고, 0이 입력된 행(103)과 다릅니다. 먼저 데이터를 준비합니다.
-- Before / After: NULL이 산술 결과에 미치는 영향SELECT SIGNUP_ID,UPPER(NICKNAME)AS NICK_UPPER,TO_CHAR(SIGNUP_DATE,'YYYY')AS SIGNUP_YEAR,
FEE - COUPON_DISCOUNT AS PAY_BEFORE,
FEE -NVL(COUPON_DISCOUNT,0)AS PAY_AFTER
FROM WORKSHOP_SIGNUP
ORDERBY SIGNUP_ID;-- 다중행 함수 비교: 여러 행을 하나의 결과 행으로 요약SELECTCOUNT(*)AS ROW_CNT,COUNT(COUPON_DISCOUNT)AS DISCOUNT_INPUT_CNT,SUM(FEE)AS FEE_SUM,ROUND(AVG(FEE),0)AS FEE_AVG,MAX(FEE)AS MAX_FEE,MIN(FEE)AS MIN_FEE
FROM WORKSHOP_SIGNUP;
TABLEBefore / After - 신청 4건의 결제액4행
SIGNUP_ID
NICK_UPPER
SIGNUP_YEAR
PAY_BEFORE
PAY_AFTER
101
MINA
2026
NULL
30000
102
JUNO
2026
35000
35000
103
SORA
2026
45000
45000
104
DAVID
2026
NULL
50000
단일행 함수만 쓴 첫 SQL은 4행 그대로 나옵니다. 집계 SQL은 1행으로 요약되어 ROW_CNT=4, DISCOUNT_INPUT_CNT=2, FEE_SUM=165000, FEE_AVG=41250, MAX_FEE=50000, MIN_FEE=30000입니다. COUNT(*)는 NULL 행도 세지만 COUNT(COUPON_DISCOUNT)는 NULL을 뺀 2건(5000과 0)만 셉니다. SUM·AVG·MAX·MIN도 NULL을 제외하고 계산합니다.