본문 바로가기

PIVOT·UNPIVOT과 정규 표현식

DB SorryP 2026. 10. 8. 18:41
반응형

SQLD 2과목의 「PIVOT 절과 UNPIVOT 절」, 「정규 표현식」 항목을 정리합니다. 행 값을 열로 펼치는 PIVOT의 문법과 암묵적 GROUP BY, IN 목록과 열 이름, PIVOT과 같은 결과를 내는 CASE·DECODE + GROUP BY, 열을 행으로 세우는 UNPIVOT과 NULL 처리, LIKE와 정규 표현식의 차이, 정규 표현식 기호, REGEXP_LIKE·REGEXP_SUBSTR·REGEXP_INSTR·REGEXP_REPLACE·REGEXP_COUNT, 마침표·탐욕 일치·대소문자 함정, SQL Server와의 차이를 쇼핑몰 예시로 살펴본 뒤 기출 유형 연습 문제 5개로 확인합니다.

앞 글 「계층형 질의와 셀프 조인」에서 한 테이블 안의 위아래 관계를 펼쳐 보았습니다. 이번 글은 두 부분입니다. 앞부분은 세로로 긴 집계 결과를 가로 표로 바꾸는 PIVOT과 그 반대인 UNPIVOT이고, 뒷부분은 LIKE보다 세밀하게 문자열 패턴을 찾는 정규 표현식입니다. PIVOT 예시는 「집합 연산자와 ROLLUP·CUBE·GROUPING SETS」의 등급 × 가격대 판매금액을 가로로 펼친 것이고, 정규 표현식 예시는 고객의 이메일·휴대폰번호와 쿠폰명 세 값입니다. 연습 문제는 실제 시험과 같은 유형으로 새로 만든 문제입니다.

1. PIVOT과 UNPIVOT 한눈에 보기

PIVOT은 판매 장부 9줄의 행 값을 열로 펼쳐 등급 B, G, S 3행 가로 표로 만들고 UNPIVOT은 휴대폰, 이메일 두 열을 행으로 세움. PIVOT에는 집계 함수가 필요

절 하는 일 집계 함수
PIVOT 행 값(가격대코드 L, M, V)을 열로 펼침. 세로 장부를 가로 표로 반드시 필요
UNPIVOT 여러 열(휴대폰번호, 이메일)을 행으로 세움. 가로 표를 세로 장부로 쓰지 않음

둘 다 FROM 절의 테이블이나 인라인 뷰 뒤에 붙습니다. PIVOT 예시의 재료는 주문상품에 주문, 고객, 상품을 잇고 가격대를 비등가 조인한 판매 내역입니다. 주문상품 11줄을 등급·주문·가격대별로 묶어 더하면 다음 9행이 되고, PIVOT은 이 금액을 등급별로 다시 더해 가로로 펼칩니다.

등급·주문 가격대코드 금액
B 5004 M 12000
B 5007 L 4000
B 5007 V 25000
G 5001 M 10000
G 5003 L 6000
G 5006 M 8000
S 5002 M 3000
S 5005 L 2000
S 5005 M 6000

고가(H) 구간의 귤은 팔리지 않았으므로 H 행은 없습니다.

2. PIVOT 문법과 결과

PIVOT 기계의 세 단계 SUM 집계, FOR 가격대코드, IN 저가 중가 선물용. 결과 등급별 3행, B는 저가 4000 중가 12000 선물용 25000, G는 6000, 18000, S는 2000, 9000이고 판매가 없는 칸은 0이 아니라 NULL, 행 합계 41000, 24000, 11000

등급별로 가격대 금액을 열로 펼칩니다.

SELECT *
  FROM (SELECT c.등급코드, g.가격대코드, oi.주문수량 * oi.주문단가 AS 금액
          FROM 주문상품 oi
          JOIN 주문 o   ON oi.주문번호 = o.주문번호
          JOIN 고객 c   ON o.고객번호 = c.고객번호
          JOIN 상품 p   ON oi.상품번호 = p.상품번호
          JOIN 가격대 g ON p.판매가 BETWEEN g.최저가 AND g.최고가)
 PIVOT (SUM(금액)                                          -- ① 칸에 들어갈 집계
        FOR 가격대코드                                      -- ② 열로 펼칠 컬럼
        IN ('L' AS 저가, 'M' AS 중가, 'V' AS 선물용))       -- ③ 펼칠 값과 열 이름
 ORDER BY 등급코드;
등급코드 저가 중가 선물용
B 4000 12000 25000
G 6000 18000 NULL
S 2000 9000 NULL
  • 행 합계는 B 41000, G 24000, S 11000으로 「집합 연산자와 ROLLUP·CUBE·GROUPING SETS」의 등급별 소계와 같습니다.
  • 판매가 없는 칸은 0이 아니라 NULL입니다. 0으로 보이려면 바깥 SELECT에서 NVL을 씌웁니다.
  • IN 목록에 'H' AS 고가를 더하면 고가 열이 생기지만 세 등급 모두 NULL입니다.
구성 규칙
집계 함수 반드시 하나 이상. 집계 없이 쓰면 오류(ORA-56902)
FOR 컬럼 열로 펼칠 기준 컬럼
IN 목록 상수 값을 직접 나열하고 별칭을 붙일 수 있음. 일반 PIVOT에서는 서브쿼리를 쓸 수 없음
IN 별칭 붙이면 별칭이 열 이름, 안 붙이면 값 그대로('L', 'M')가 열 이름
IN 목록에 없는 값 결과에서 버려짐. IN ('L' AS 저가)만 쓰면 저가 열 하나만 나옴
그 밖의 컬럼 PIVOT에 쓰이지 않은 컬럼은 모두 암묵적 GROUP BY 기준

3. 암묵적 GROUP BY와 CASE·DECODE 방식

PIVOT은 괄호 밖에 남은 컬럼으로 알아서 묶어 주문번호가 남으면 3행이 아니라 7행. CASE나 DECODE에 GROUP BY를 직접 써도 같은 3행

원본에 컬럼이 더 있으면 행이 늘어납니다

PIVOT은 집계 함수와 FOR 컬럼에 쓰이지 않은 나머지 컬럼으로 알아서 GROUP BY를 합니다. 원본 인라인 뷰에 주문번호를 하나 더 넣으면 그룹 기준이 (등급코드, 주문번호)가 되어 3행이 7행으로 늘어납니다.

등급·주문 저가 중가 선물용
B 5004 NULL 12000 NULL
B 5007 4000 NULL 25000
G 5001 NULL 10000 NULL
G 5003 6000 NULL NULL
G 5006 NULL 8000 NULL
S 5002 NULL 3000 NULL
S 5005 2000 6000 NULL
  • 그래서 PIVOT은 보통 필요한 컬럼만 고른 인라인 뷰에 겁니다. 테이블에 바로 걸면 남은 컬럼 전부가 그룹 기준이 됩니다.
  • 예를 들어 SELECT * FROM 상품 PIVOT (COUNT(*) FOR 판매가 IN (4000 AS 사천원))은 상품번호, 상품명별로 묶여 6행이 나오고, 사천원 열은 P20과 P50만 1입니다.

집계 함수를 여러 개 쓰기

PIVOT (SUM(금액) AS 금액, COUNT(*) AS 건수 FOR 가격대코드 IN ('M' AS 중가))처럼 집계 함수를 둘 이상 쓰면 열 이름은 「IN 별칭_집계 별칭」이 됩니다. 집계 함수가 둘 이상이면 집계 별칭을 붙입니다.

등급코드 중가_금액 중가_건수
B 12000 2
G 18000 3
S 9000 2

PIVOT 이전 방식: CASE·DECODE + GROUP BY

SELECT 등급코드,
       SUM(CASE WHEN 가격대코드 = 'L' THEN 금액 END) AS 저가,
       SUM(CASE WHEN 가격대코드 = 'M' THEN 금액 END) AS 중가,
       SUM(CASE WHEN 가격대코드 = 'V' THEN 금액 END) AS 선물용
  FROM (2장의 인라인 뷰)
 GROUP BY 등급코드;
  • 결과는 2장의 PIVOT과 똑같습니다. SUM(DECODE(가격대코드, 'L', 금액))도 같고, NVL(SUM(...), 0)을 씌우면 NULL 칸이 0이 됩니다.
  • 「SQL 함수, 문자·숫자·날짜·NULL 함수와 CASE」의 CASE·DECODE와 「GROUP BY와 HAVING, 집계 함수와 NULL」의 GROUP BY를 합친 모양입니다. 시험에서는 「PIVOT과 같은 결과를 내는 SQL 고르기」로 나옵니다. CASE 방식은 GROUP BY를 직접 써야 하고, PIVOT은 GROUP BY를 쓰지 않는다는 점이 다릅니다.

4. UNPIVOT과 NULL

UNPIVOT은 NULL 칸을 버려 고객 5명 2열 10칸에서 C02, C04의 빈 이메일이 빠져 8행. INCLUDE NULLS를 쓰면 10행, PIVOT과 UNPIVOT은 정확한 역연산이 아님

고객의 휴대폰번호와 이메일 두 열을 「연락수단, 연락처」 두 컬럼의 행으로 세웁니다.

SELECT 고객번호, 연락수단, 연락처
  FROM 고객
UNPIVOT (연락처                                          -- ① 값이 들어갈 새 컬럼
         FOR 연락수단                                     -- ② 원래 열 이름이 들어갈 새 컬럼
         IN (휴대폰번호 AS '휴대폰', 이메일 AS '이메일'));  -- ③ 세울 열들
고객번호 연락수단 연락처
C01 휴대폰 01011110001
C01 이메일 hana@example.com
C02 휴대폰 01022220002
C03 휴대폰 01033330003
C03 이메일 semi@example.com
C04 휴대폰 01044440004
C05 휴대폰 01055550005
C05 이메일 dasom@example.co.kr
  • 고객 5명 × 2열 = 10칸이지만 결과는 8행입니다. 이메일이 NULL인 C02, C04의 이메일 행은 기본으로 빠집니다. UNPIVOT INCLUDE NULLS (...)로 쓰면 10행이고 두 행의 연락처가 NULL입니다.
  • IN 목록에 별칭이 없으면 연락수단 값은 열 이름 그대로(휴대폰번호, 이메일)입니다.
  • 세우는 열들은 데이터 타입이 같아야 합니다. IN (상품명, 판매가)처럼 문자와 숫자를 섞으면 오류(ORA-01790)입니다.
  • PIVOT 결과를 다시 UNPIVOT하면 NULL 칸이 사라져 7행(B 3, G 2, S 2)만 돌아오고, 합쳐지기 전의 9행도 되살아나지 않습니다. PIVOT과 UNPIVOT은 정확한 역연산이 아닙니다.
  • UNPIVOT 이전 방식은 UNION ALL입니다. SELECT 고객번호, '휴대폰', 휴대폰번호 FROM 고객 UNION ALL SELECT 고객번호, '이메일', 이메일 FROM 고객 WHERE 이메일 IS NOT NULL이 같은 8행입니다.

5. 정규 표현식과 LIKE의 차이

LIKE는 퍼센트와 밑줄 두 와일드카드만 써서 밑줄 찾기에 쿠폰 3개 모두 걸리고, 정규 표현식에서 밑줄은 보통 글자라 K01, K03만 일치. 정규 표현식은 마침표가 아무 글자 하나이고 부분 일치

「WHERE 절과 ORDER BY, Top N 쿼리」의 LIKE는 %(0글자 이상)와 _(정확히 1글자) 두 와일드카드만 씁니다. 정규 표현식은 「숫자 3개」, 「영문 소문자로 시작」, 「@ 앞부분」처럼 훨씬 세밀한 패턴을 씁니다. 오라클 정규 표현식은 POSIX 표준을 따르고, \d 같은 Perl식 표현도 일부 지원합니다.

비교 LIKE 정규 표현식
아무 글자 1개 _ .
아무 글자 0개 이상 % .*
일치 범위 패턴이 문자열 전체와 맞아야 함 패턴이 문자열 어디든 있으면 일치. 전체는 ^와 $로 감쌈
_ 찾기 LIKE '%_%'는 쿠폰 3개 모두(_가 아무 글자) REGEXP_LIKE(쿠폰명, '_')는 K01, K03(밑줄 글자)
  • 정규 표현식에서 _와 %는 보통 글자이고, .이 「아무 글자 하나」입니다. 기호의 뜻이 LIKE와 다릅니다.
  • 「WHERE 절과 ORDER BY, Top N 쿼리」에서는 밑줄을 글자로 찾으려고 LIKE '%\_%' ESCAPE '\'를 썼습니다. 정규 표현식에서는 _가 처음부터 보통 글자라 이스케이프가 필요 없고, 반대로 마침표를 글자로 찾을 때 \.이 필요합니다.

6. 정규 표현식 기호

정규 표현식 기호 도감. 마침표는 아무 글자 하나, 별표는 0회 이상, 더하기는 1회 이상, 물음표는 0회 또는 1회, 모자 기호는 시작, 달러는 끝, 대괄호 안 모자 기호는 아닌 것. 더하기 패턴에는 여름_10%할인만 일치

기호 뜻 예
. 아무 글자 1개 '^.$'는 한 글자 상품명 배, 감, 귤
* 앞 요소 0회 이상 '^여름_*10'은 여름_10%할인, 여름10할인
+ 앞 요소 1회 이상 '^여름_+10'은 여름_10%할인만
? 앞 요소 0회 또는 1회 '^여름_?10'은 여름_10%할인, 여름10할인
{m}, {m,}, {m,n} 정확히 m회, m회 이상, m회 이상 n회 이하 '^010[[:digit:]]{8}$'는 휴대폰번호 5개 모두
[ ] 괄호 안 글자 중 하나 [a-z]는 영문 소문자 하나
[^ ] 괄호 안 글자가 아닌 글자 하나 '[^@]+$'는 @ 뒤 도메인
^ 문자열 시작 '^배'는 배, 배 선물세트
$ 문자열 끝 '\.com$'은 .com으로 끝나는 이메일(C01, C03)
( ) 묶음(하위 표현식) '(\d{3})(\d{4})(\d{4})'
\n(n은 1~9) n번째 묶음과 같은 문자열(역참조) '(\d)\1\1\1'은 1111, 2222처럼 같은 숫자 4개
\ 다음 기호를 글자 그대로 '\.'은 마침표 글자
[:digit:], [:alpha:], [:space:] 문자 클래스. 대괄호 안에 씀 [[:digit:]]는 숫자 하나
\d, \s, \w 숫자, 공백, 단어 글자. 대문자(\D, \S, \W)는 그 반대 \s를 지우면 배선물세트
  • 「또는」은 세로 막대 기호 |입니다. '사과|배'는 사과, 배, 청사과, 배 선물세트와 일치합니다.
  • ^는 두 가지 뜻입니다. 패턴 맨 앞에서는 「시작」, 대괄호 안 맨 앞에서는 「아닌 것」입니다. '^[^배]'는 배로 시작하지 않는 상품 4개(사과, 감, 귤, 청사과)입니다.
  • *?, +?처럼 뒤에 ?를 붙이면 가능한 한 짧게 일치하는 최소 일치가 됩니다(8장).

7. REGEXP 함수 다섯 가지

REGEXP 함수 다섯 가지 공구함. REGEXP_LIKE는 WHERE 등에 쓰는 조건, SUBSTR은 부분 문자열 hana, INSTR은 골뱅이 위치 5, REPLACE는 01011110001을 010-1111-0001로 바꾸기, COUNT는 마침표 2개처럼 횟수

함수 형식 돌려주는 것
REGEXP_LIKE REGEXP_LIKE(원본, 패턴 [, 옵션]) 조건(참·거짓). WHERE 절 등 조건 자리에 씀
REGEXP_SUBSTR REGEXP_SUBSTR(원본, 패턴 [, 시작위치 [, 몇번째 [, 옵션 [, 묶음번호]]]]) 일치한 부분 문자열
REGEXP_INSTR REGEXP_INSTR(원본, 패턴 [, 시작위치 [, 몇번째 [, 반환옵션 [, 옵션 [, 묶음번호]]]]]) 위치. 반환옵션 0은 시작 위치, 1은 끝 다음 위치
REGEXP_REPLACE REGEXP_REPLACE(원본, 패턴 [, 바꿀문자 [, 시작위치 [, 몇번째 [, 옵션]]]]) 바꾼 문자열. 몇번째를 생략하거나 0이면 전부
REGEXP_COUNT REGEXP_COUNT(원본, 패턴 [, 시작위치 [, 옵션]]) 일치 횟수
  • 옵션은 'i' 대소문자 무시, 'c' 대소문자 구분, 'n' 마침표가 줄바꿈과도 일치, 'm' 여러 줄 모드입니다. 생략하면 보통 대소문자를 구분합니다.
  • 원본이 NULL이면 결과도 NULL입니다. 이메일이 NULL인 C02, C04는 REGEXP_SUBSTR, REGEXP_COUNT 모두 NULL입니다.

이메일 예

C01은 hana@example.com, C05는 dasom@example.co.kr입니다.

식 C01 C05
REGEXP_SUBSTR(이메일, '^[^@]+') hana dasom
REGEXP_SUBSTR(이메일, '[^@]+$') example.com example.co.kr
REGEXP_SUBSTR(이메일, '[^.]+', 1, 2) com co
REGEXP_SUBSTR(이메일, '[^.]+', 1, 3) NULL kr
REGEXP_SUBSTR(이메일, '([^@]+)@(.+)', 1, 1, NULL, 2) example.com example.co.kr
REGEXP_INSTR(이메일, '@') 5 6
REGEXP_INSTR(이메일, 'example') 6 7
REGEXP_INSTR(이메일, 'example', 1, 1, 1) 13 14
REGEXP_COUNT(이메일, '\.') 1 2
REGEXP_LIKE(이메일, '^[a-z]+@[a-z]+\.[a-z]+$') 일치 불일치(점이 두 개)
REGEXP_LIKE(이메일, '^[a-z]+@[a-z]+(\.[a-z]+)+$') 일치 일치
  • '[^.]+'은 「마침표가 아닌 글자 1개 이상」이라 마침표로 나뉜 조각을 뜻합니다. 대괄호 안의 마침표는 글자 그대로입니다.
  • 마지막 줄의 (\.[a-z]+)+는 「마침표 + 영문자」 묶음이 1번 이상이라 .co.kr도 일치합니다.

휴대폰번호 예(C01, 01011110001)

식 결과
REGEXP_REPLACE(휴대폰번호, '(\d{3})(\d{4})(\d{4})', '\1-\2-\3') 010-1111-0001
REGEXP_REPLACE(휴대폰번호, '1', '*') 0*0****000*(전부)
REGEXP_REPLACE(휴대폰번호, '1', '*', 1, 1) 0*011110001(첫 번째만)
REGEXP_REPLACE(휴대폰번호, '1', '*', 1, 2) 010*1110001(두 번째만)
REGEXP_REPLACE(휴대폰번호, '1', '*', 5) 0101***000*(5번째 글자부터 전부)
REGEXP_SUBSTR(휴대폰번호, '(\d)\1\1\1') 1111

쿠폰명 예

쿠폰명 세 값(여름_10%할인, 여름10할인, 가을_5%할인)은 「WHERE 절과 ORDER BY, Top N 쿼리」의 ESCAPE 예와 같습니다.

식 K01, K02, K03 결과
REGEXP_SUBSTR(쿠폰명, '\d+') 10, 10, 5
REGEXP_REPLACE(쿠폰명, '[^0-9]', '') 10, 10, 5
REGEXP_LIKE(쿠폰명, '\d+%') 일치, 불일치, 일치
REGEXP_LIKE(쿠폰명, '_') 일치, 불일치, 일치

8. 정규 표현식 함정 세 가지

정규 표현식 함정. 마침표는 아무 글자라 hana@examplecom에도 일치하므로 마침표 이스케이프 필요, 기본은 가능한 길게 일치해 dasom@example.co.이고 최소 일치는 dasom@example., 대소문자는 i 옵션으로 무시

함정 예 결과
마침표를 이스케이프하지 않음 REGEXP_LIKE('hana@examplecom', '.com$') 일치(.이 아무 글자라 e와 일치)
마침표를 이스케이프함 REGEXP_LIKE('hana@examplecom', '\.com$') 불일치
탐욕(greedy) 일치 REGEXP_SUBSTR('dasom@example.co.kr', '.+\.') dasom@example.co.(가능한 길게)
최소(nongreedy) 일치 REGEXP_SUBSTR('dasom@example.co.kr', '.+?\.') dasom@example.(가능한 짧게)
대소문자 구분 WHERE REGEXP_LIKE(이메일, 'HANA') 0행
옵션 i로 무시 WHERE REGEXP_LIKE(이메일, 'HANA', 'i') C01 1행
  • 실제 데이터의 C01, C03 이메일은 '.com$'과 '\.com$'의 결과가 같아서(둘 다 2행) 차이가 보이지 않습니다. 시험은 이런 「우연히 맞는 패턴」을 보기로 냅니다.
  • +, *는 기본으로 가능한 한 길게 일치합니다. 짧게 끊으려면 +?, *?를 씁니다.

9. SQL Server와의 차이

PIVOT과 정규 표현식의 SQL Server 차이 사전. PIVOT IN 목록은 대괄호 열 이름, UNPIVOT에 INCLUDE NULLS 없음, 정규 표현식은 최근 버전부터 지원하고 LIKE 대괄호 패턴을 씀, 시험은 오라클 기준

항목 오라클 SQL Server
PIVOT IN 목록 값 리터럴 IN ('L' AS 저가, ...) 열 이름 식별자 IN ([L], [M], [V])
PIVOT 결과 별칭 생략 가능 원본 파생 테이블과 PIVOT 결과에 별칭 필요
UNPIVOT의 NULL 기본 제외, INCLUDE NULLS로 포함 제외(INCLUDE NULLS 옵션 없음)
UNPIVOT 열 타입 같은 타입 계열 타입과 길이까지 같아야 함(CAST로 맞춤)
정규 표현식 REGEXP 함수 다섯 가지 오랫동안 없었고 최근 버전부터 지원. LIKE의 대괄호 패턴을 씀
  • SQL Server에서 같은 PIVOT을 쓰면 값은 오라클과 같고 열 이름이 L, M, V가 됩니다.
  • SQL Server의 LIKE는 [0-9], [^a] 같은 대괄호 패턴을 쓸 수 있습니다. 예를 들어 휴대폰번호 LIKE '010[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'는 5행입니다. 시험의 정규 표현식 문제는 오라클 기준입니다.

10. 헷갈리기 쉬운 점

PIVOT과 정규 표현식의 헷갈리기 쉬운 점 다트 판. PIVOT은 남은 컬럼으로 묶음, PIVOT 빈칸은 NULL, UNPIVOT은 NULL을 버림, 정규 표현식은 부분 일치, 별표는 0회도 됨, REGEXP_LIKE는 조건

  • PIVOT은 남은 컬럼으로 묶습니다. 원본에 컬럼이 하나 더 있으면 행 수가 늘어납니다. 결과 행 수 문제는 PIVOT 괄호 밖에 남은 컬럼을 셉니다.
  • PIVOT의 빈칸은 NULL입니다. 0으로 보이려면 바깥 SELECT에서 NVL을 쓰거나, CASE 방식에서 ELSE 0을 씁니다.
  • UNPIVOT은 NULL 칸을 버립니다. 5명 × 2열 = 10이 아니라 8입니다. 포함하려면 INCLUDE NULLS를 씁니다.
  • 정규 표현식은 부분 일치입니다. REGEXP_LIKE(상품명, '배')는 배, 배 선물세트와 모두 일치합니다. 전체 일치는 ^와 $로 감쌉니다.
  • ^는 두 가지 뜻입니다. 패턴 맨 앞은 「시작」, 대괄호 안 맨 앞은 「아닌 것」입니다.
  • *는 0회도 됩니다. '^여름_*10'은 밑줄이 없는 여름10할인과도 일치합니다. 1회 이상은 +입니다.
  • 정규 표현식의 마침표는 아무 글자입니다. 마침표 글자를 찾으려면 \.으로 씁니다. 반대로 _와 %는 보통 글자입니다.
  • REGEXP_REPLACE의 몇번째 인수를 생략하면 전부 바꿉니다. 첫 번째만 바꾸려면 시작위치 1, 몇번째 1을 줍니다.
  • REGEXP_LIKE는 조건입니다. 값을 돌려주는 다른 네 함수와 달리 WHERE 절 등 조건 자리에 씁니다.

11. 연습 문제

PIVOT과 정규 표현식 연습 문제 큐브 퍼즐 장면. 문제 5개, 풀이는 아래에, 다음은 관리 구문

PIVOT의 결과 행 수, UNPIVOT과 NULL, 정규 표현식 패턴과 함수 결과를 확인하는 문제입니다. 실제 시험과 같은 유형으로 새로 만들었습니다. 정답과 풀이는 다음 장에 있으니, 먼저 직접 풀어 보세요.

문제 1. [판매] 테이블이 다음과 같을 때, 두 SQL의 결과 행 수를 차례로 고르면?

[판매]

등급코드 주문번호 가격대코드 금액
B 5004 M 12000
B 5007 L 4000
B 5007 V 25000
G 5001 M 10000
G 5003 L 6000
G 5006 M 8000
S 5002 M 3000
S 5005 L 2000
S 5005 M 6000
-- (가)
SELECT *
  FROM (SELECT 등급코드, 가격대코드, 금액 FROM 판매)
 PIVOT (SUM(금액) FOR 가격대코드 IN ('L' AS 저가, 'M' AS 중가, 'V' AS 선물용));

-- (나)
SELECT *
  FROM 판매
 PIVOT (SUM(금액) FOR 가격대코드 IN ('L' AS 저가, 'M' AS 중가, 'V' AS 선물용));

① 3, 3
② 3, 7
③ 3, 9
④ 9, 9

문제 2. [고객] 테이블이 다음과 같을 때, SQL의 결과 행 수는?

[고객]

고객번호 휴대폰번호 이메일
C01 01011110001 hana@example.com
C02 01022220002 NULL
C03 01033330003 semi@example.com
C04 01044440004 NULL
C05 01055550005 dasom@example.co.kr
SELECT 고객번호, 연락수단, 연락처
  FROM 고객
UNPIVOT (연락처 FOR 연락수단 IN (휴대폰번호, 이메일));

① 5
② 8
③ 10
④ 오류가 발생한다

문제 3. 문제 2의 [고객] 테이블에서 다음 SQL의 결과 행 수는?

SELECT 고객번호
  FROM 고객
 WHERE REGEXP_LIKE(이메일, '^[a-z]+@[a-z]+\.[a-z]+$');

① 2
② 3
③ 4
④ 5

문제 4. [쿠폰] 테이블의 쿠폰명이 '여름_10%할인', '여름10할인', '가을_5%할인' 세 개일 때, '여름_10%할인' 한 행만 일치하는 조건은?

① REGEXP_LIKE(쿠폰명, '_')
② REGEXP_LIKE(쿠폰명, '^여름_?10')
③ REGEXP_LIKE(쿠폰명, '^여름_*10')
④ REGEXP_LIKE(쿠폰명, '^여름_+10')

문제 5. 정규 표현식에 대한 설명으로 가장 적절하지 않은 것은?

① REGEXP_COUNT('dasom@example.co.kr', '\.')의 결과는 2이다.
② REGEXP_SUBSTR('hana@example.com', '[^@]+$')의 결과는 'example.com'이다.
③ 정규 표현식에서 .은 마침표 한 글자만 뜻하므로 REGEXP_LIKE('hana@examplecom', '.com$')은 거짓이다.
④ REGEXP_INSTR('hana@example.com', '@')의 결과는 5이다.

12. 풀이

문제 1. 정답 ②
(가)는 인라인 뷰에 등급코드, 가격대코드, 금액만 있으므로 등급코드로만 묶여 3행입니다(B 4000·12000·25000, G 6000·18000·NULL, S 2000·9000·NULL). (나)는 PIVOT에 쓰이지 않은 주문번호도 그룹 기준이 되어 (등급코드, 주문번호) 조합 7행입니다.

문제 2. 정답 ②
5명 × 2열 = 10칸 중 이메일이 NULL인 2칸은 기본으로 제외되어 8행입니다. UNPIVOT INCLUDE NULLS라면 10행입니다.

문제 3. 정답 ①
C01, C03은 일치합니다. C05는 @ 뒤에 마침표가 두 개라 [a-z]+\.[a-z]+$와 맞지 않고, C02와 C04는 이메일이 NULL이라 조건이 참이 되지 않습니다.

문제 4. 정답 ④
_+는 밑줄이 1개 이상이어야 하므로 '여름_10%할인'만 일치합니다. ①은 밑줄이 있는 K01, K03 두 행이고, ②의 _?(0회 또는 1회)와 ③의 _*(0회 이상)는 밑줄이 없는 '여름10할인'까지 두 행입니다.

문제 5. 정답 ③
정규 표현식의 .은 「아무 글자 하나」라서 'examplecom'의 e와 일치하므로 참입니다. 마침표 글자만 찾으려면 \.com$으로 쓰고, 이때는 거짓입니다. ①은 마침표 2개, ②는 @ 뒤 전체, ④는 @의 위치 5로 모두 맞는 설명입니다.

마치며

이번 글에서는 PIVOT·UNPIVOT과 정규 표현식을 정리했습니다.

  • PIVOT은 행 값을 열로 펼치며, 집계 함수가 반드시 있어야 하고 PIVOT에 쓰이지 않은 컬럼이 모두 그룹 기준이 됩니다. 예시에서 인라인 뷰로 고르면 3행, 주문번호가 남으면 7행입니다.
  • PIVOT의 빈칸은 NULL이고, 같은 결과를 CASE·DECODE + GROUP BY로도 만들 수 있습니다.
  • UNPIVOT은 열을 행으로 세우며 기본으로 NULL을 버립니다. 고객 5명 × 2열에서 8행, INCLUDE NULLS면 10행입니다.
  • 정규 표현식은 부분 일치이고, .은 아무 글자, *는 0회 이상, +는 1회 이상, ?는 0회 또는 1회, ^와 $는 시작과 끝입니다.
  • REGEXP_LIKE는 조건이고, REGEXP_SUBSTR·REGEXP_INSTR·REGEXP_REPLACE·REGEXP_COUNT는 값을 돌려줍니다. REGEXP_REPLACE는 몇번째를 생략하면 전부 바꿉니다.

다음 글 「관리 구문, DML·TCL·DDL·DCL 정리」에서는 데이터를 넣고 고치고 지우는 DML과 MERGE, COMMIT·ROLLBACK·SAVEPOINT, CREATE·ALTER·DROP·TRUNCATE와 제약조건, GRANT·REVOKE와 ROLE을 쇼핑몰 예시로 살펴보고 기출 유형 문제로 확인합니다.

참고 자료(공식)

반응형