์๋ ํ์ธ์ yunamom ์ ๋๋ค. ^^
์ค๋์ 2024๋ ๋ถํฐ SQLD ์ํ 2๊ณผ๋ชฉ SQL ํ์ฉ ์ ์๋กญ๊ฒ ์ถ๊ฐ๋ ๋ฌธ์ ์ ํ PIVOT, UNPIVOT ์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.

1. PIVOT
๋จผ์ PIVOT ์ ์ง์ญํ๋ฉด ์ค์ฌ์ถ, ๋๋ ํ์ ํ๋ค, ๋ฐฉํฅ์ ์ ํํ๋ค ๋ผ๋ ๋ป์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๋ณดํต PIVOT์ ์ค๋ช ํ ๋ "ํ์ ์ด๋ก ์ ํํด์ ๋ฐ์ดํฐ๋ฅผ ์ฌ๊ตฌ์ฑํ๋ค" ๋ผ๊ณ ํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด.. ์ด๋๊ฐ ์ค์ฌ์ด๊ณ , ์ด๋ป๊ฒ ํ์ ํ๋ ๊ฑธ๊น์? ํ๊ณผ ์ด, ์ฆ ๊ฐ๋ก์ ์ธ๋ก๋ ์ด๋ค ๊ฑธ ์๋ฏธํ ๊น์?
์ฌ๊ธฐ์ ๋จผ์ ์์์ผ ํ ๊ฒ์ -> ํ(Row) = ๊ฐ๋ก, ์ด(Column) = ์ธ๋ก ์ ๋๋ค.
๊ทธ๋ฐ๋ฐ ์ด์ํ์ฃ ? "ํ์ ์ด๋ก ๋ฐ๊พผ๋ค" ๋ฉด์ ์ ๊ฒฐ๊ณผ๋ ๊ฐ๋ก๋ก ํผ์ณ์ง๊น์?
์ฒ์ ์ ํ๋ฉด ์ ๋ง ํท๊ฐ๋ฆด ์ ๋ฐ์ ์์ต๋๋ค. (์ ๊ฐ ๊ทธ๋ฌ์ต๋๋ค. ใ ใ )
์ด์ PIVOT ์ ๊ธฐ๋ณธ ๋ฌธ๋ฒ๊ณผ ์์ ๋ฅผ ์ดํด๋ณด๋ฉฐ ์ฒ์ฒํ ์ดํดํด๋ด ์๋ค.
PIVOT ๊ธฐ๋ณธ ๋ฌธ๋ฒ (์ค๋ผํด)
SELECT ์ปฌ๋ผ๋ชฉ๋ก
FROM (
SELECT ์๋ณธ์ปฌ๋ผ๋ค
FROM ํ
์ด๋ธ๋ช
)
PIVOT (
์ง๊ณํจ์(๊ฐ์ปฌ๋ผ)
FOR ๊ธฐ์ค์ปฌ๋ผ IN (
'๊ฐ1' AS ์์ปฌ๋ผ1,
'๊ฐ2' AS ์์ปฌ๋ผ2,
...
)
);
- ์ง๊ณํจ์: ๋ณดํต SUM, MAX, COUNT ๋ฑ์ ์ฌ์ฉ (*ํ์)
- ๊ฐ์ปฌ๋ผ: ์ค์ ๋ก ์ง๊ณํ ์ซ์๋ ์์น ๋ฐ์ดํฐ
- ๊ธฐ์ค์ปฌ๋ผ: ํผ๋ฒ ๊ธฐ์ค์ด ๋๋ ์ด (์: ๋ ์ง, ์นดํ ๊ณ ๋ฆฌ ๋ฑ)
- IN์ : ์ด๋ค ๊ฐ๋ค์ ์๋ก์ด ์ด๋ก ๋ฐ๊ฟ์ง ์ง์ '๊ฐ' AS ์์ปฌ๋ผ์ด๋ฆ ํ์
PIVOT ์์
SELECT *
FROM (
SELECT ํ๋ชฉ, ๋ ์ง, ๊ฐ๊ฒฉ
FROM ๊ณผ์ผ_ํ๋งค
)
PIVOT (
MAX(๊ฐ๊ฒฉ)
FOR ๋ ์ง IN (
'Y2025_07' AS "202507",
'Y2025_08' AS "202508",
'Y2025_09' AS "202509"
)
);
- ํ๋ชฉ๋ณ๋ก ์๋ณ ์ต๊ณ ๊ฐ๊ฒฉ(MAX)์ ๊ฐ๋ก ๋ฐฉํฅ์ผ๋ก
- 'Y2025_07'์ด๋ผ๋ ๋ ์ง ๊ฐ์ "202507"์ด๋ผ๋ ์๋ก์ด ์ปฌ๋ผ๋ช ์ผ๋ก ๋ฐ๊ฟ์ค (์ค๋ผํด ์ซ์ ๋ฐ์ดํฐ " " , MS-SQL ์ [ ] ๋ก ๊ฐ์ธ์ค์ผํจ.)

ํด๋น ํ๋ฅผ ๋ณด๋ฉด PIVOT ์ดํ์ ๋ฐ์ดํฐ๊ฐ ์ง๊ด์ ์ด๊ณ ๋ณด๊ธฐ ํธํ๋ค๋๊ฒ์ ๋จ๋ฒ์ ์์ ์์ต๋๋ค.
๊ทธ๋์ ์ด๋ฐ ์๊ฐ์ด ๋ค ์๋ ์์ด์. "์ฒ์๋ถํฐ ์ด๋ ๊ฒ PIVOT ํํ๋ก ํ ์ด๋ธ์ ๋ง๋ค๋ฉด ๋ ์ฝ์ง ์์๊น?"
ํ์ง๋ง ์ค์ ๋ก ๋๋ถ๋ถ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ ์ด๋ธ ๊ตฌ์กฐ๋ PIVOT ์ LONG DATA ์ค๊ณ๋ฅผ ํ๊ณ ์์ง์ ์ ๊ทธ๋ด๊น์?
| ๊ตฌ๋ถ | ์ค๋ช | |
| PIVOT ์ | LONG DATA | - **ํ(Row) ์ ์์์ ํํ - ๋ฐ์ดํฐ๋ฅผ ์๋↓๋ก ์ค์ค์ด ์์๊ฐ๋ค - ์ ๊ทํ๋ ๊ตฌ์กฐ (DB ์นํ์ ) - ๋ค๋ฅธ ํ ์ด๋ธ๊ณผ์ JOIN ์ฐ์ฐ ๊ฐ๋ฅ |
| PIVOT ํ | WIDE DATA | - **์ด(Column) ์ ๋์ดํด์ ํํ - ํญ๋ชฉ์ ์→์ผ๋ก ๋๋ ค ๊ฐ๋ค. - ๋น์ ๊ทํ ๊ตฌ์กฐ - JOIN ๋ถ๊ฐ๋ฅ |
๊ทธ ์ด์ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชฉ์ ์ด '๋ณด๊ธฐ ์ข๊ฒ ์ ๋ฆฌํ๋ ๊ฒ'์ด ์๋๋ผ, 'ํจ์จ์ ์ผ๋ก ์ ์ฅ, ์ฒ๋ฆฌ, ํ์ฅํ๋ ๊ฒ' ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด์ ๋ฐ๋ผ ์๊ฐ์์ผ๋ก ์์ด๋ ๊ฐ์ด๋ ๋๊ท๋ชจ ์ธ์์ ์ ๋ณด๋ PIVOT์ ํ์ฉํด ์ผ์์ ์ผ๋ก ๊ตฌ์กฐ๋ฅผ ์ ํํจ์ผ๋ก์จ, ๋ณด๊ณ ์๋ ์๊ฐํ์์ ๊ฐ๋ ์ฑ์ ๋์ด๋ ๋ฐ ํ์ฉ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ํ์ฌ ์ง์ ์ ๋ณด๋ ํ์ ์ฑ์ , ์ ํ ํ๋งค ๊ธฐ๋ก์ฒ๋ผ ์๊ฐ์ด ์ง๋ ์๋ก ๋์ ๋๋ ๋ฐ์ดํฐ๋ ๋๋ถ๋ถ LONG ํํ๋ก ์ ์ฅ๋ฉ๋๋ค.
PIVOT ๋ฌธ์ ๋ฅผ ์ฒ์ ๋ณด๋ฉด ์ฟผ๋ฆฌ๋ฌธ์ด ๊ธธ๊ณ ๋ณต์กํด ๋ณด์ฌ์ ์์ํ๊ณ ๋ถ๋ด์ค๋ฝ๊ฒ ๋๊ปด์ง ์ ์๋๋ฐ์.PIVOT ์ ์ ์ฌ์ฉํด์ผํ๋์ง ์ด ๊ฐ๋ ๋ง ์ ๋๋ก ์ดํดํ๊ณ ๋๋ฉด, PIVOT ๋ฌธ์ ๋ฅผ ์ ํ ๋ ํจ์ฌ ๋ ํธํ๊ฒ ์ ๊ทผํ ์ ์์ต๋๋ค.๐
2. UNPIVOT
UNPIVOT ์ด๋ UN + PIVOT = PIVOT ์ ํด์ ํ๋ค. ์ฆ, ์ด(Column) ์ ํ(Row) ์ผ๋ก ๋๋๋ฆฌ๋ ์์ ์ ๋๋ค.
UNPIVOT ๊ธฐ๋ณธ ๋ฌธ๋ฒ (์ค๋ผํด)
SELECT ์ปฌ๋ผ1, ์ปฌ๋ผ2, ...
FROM ํ
์ด๋ธ๋ช
UNPIVOT (
๊ฐ์ด๋ค์ด๊ฐ์ปฌ๋ผ FOR ๊ธฐ์ค์ปฌ๋ผ IN (๊ธฐ์กด์ ์ด ๋ชฉ๋ก)
);
UNPIVOT ์์
SELECT ํ๋ชฉ, ๋ ์ง, ๊ฐ๊ฒฉ
FROM ๊ณผ์ผ_๊ฐ๊ฒฉ
UNPIVOT (
๊ฐ๊ฒฉ
FOR ๋ ์ง IN (
Y2025_07,
Y2025_08,
Y2025_09
)
);

๊ทธ๋ ๋ค๋ฉด ์ด๋ค ์ํฉ์์ UNPIVOT์ด ํ์ํ ๊น์?
- ์์ ๋ฑ์์ ํผ๋ฒ๋ ํํ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ ๋
- ์๊ฐํ๋ ๋ณด๊ณ ์ฉ์ผ๋ก ๋ง๋ ๋ฐ์ดํฐ๋ฅผ ๋ค์ SQL ๋ถ์์ฉ์ผ๋ก ๋๋๋ฆด ๋
- ์ธ๋ถ ์์คํ /API์์ WIDE ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ๋๊ฒจ์ฃผ๋ ๊ฒฝ์ฐ
| ๊ตฌ๋ถ | ์ค๋ช | |
| UNPIVOT ์ | WIDE DATA | - **์ด(Column)**์ ๋์ดํด์ ํํ - ํญ๋ชฉ์ ์→์ผ๋ก ๋๋ ค ๊ฐ๋ค - ๋น์ ๊ทํ ๊ตฌ์กฐ - JOIN, ์ง๊ณ, ์กฐ๊ฑด๋ฌธ ์ฒ๋ฆฌ์ ๋ถ๋ฆฌ |
| UNPIVOT ํ | LONG DATA | - **ํ(Row)**์ ์์์ ํํ - ๋ฐ์ดํฐ๋ฅผ ์๋↓๋ก ์ค์ค์ด ์์๊ฐ๋ค - ์ ๊ทํ๋ ๊ตฌ์กฐ (DB ์นํ์ ) - ๋ค๋ฅธ ํ ์ด๋ธ๊ณผ์ JOIN ์ฐ์ฐ ๊ฐ๋ฅ, SQL ๋ถ์์ ์ ๋ฆฌ |
์ฆ, PIVOT๋ ๋ณด๊ธฐ ์ข์ ํํ์ ๋ฐ์ดํฐ ๋ฅผ ๊ฐ์ ธ์์ ๋, ๊ทธ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๋ถ์ ๊ฐ๋ฅํ ์๋ ํํ๋ก ๋ฐ๊พธ๊ธฐ ์ํด UNPIVOT ์ ํฉ๋๋ค.
3. MS-SQL PIVOT, UNPIVOT
*์ค๋ผํด ๊ณผ MS-SQL ์ PIVOT ์ฐจ์ด์ ์ ์์๋ณด๊ธฐ
PIVOT ๊ธฐ๋ณธ ๋ฌธ๋ฒ (MS-SQL)
SELECT ๊ณ ์ ์ปฌ๋ผ, ๊ฐ1, ๊ฐ2, ...
FROM (
SELECT ๊ณ ์ ์ปฌ๋ผ, ๊ธฐ์ค์ปฌ๋ผ, ๊ฐ์ปฌ๋ผ
FROM ํ
์ด๋ธ๋ช
) AS ์์ค
PIVOT (
์ง๊ณํจ์(๊ฐ์ปฌ๋ผ)
FOR ๊ธฐ์ค์ปฌ๋ผ IN (๊ฐ1, ๊ฐ2, ...)
) AS ๊ฒฐ๊ณผ๋ณ์นญ;
UNPIVOT ๊ธฐ๋ณธ ๋ฌธ๋ฒ (MS-SQL)
SELECT ๊ณ ์ ์ปฌ๋ผ, ๊ธฐ์ค์ปฌ๋ผ, ๊ฐ์ปฌ๋ผ
FROM (
SELECT ๊ณ ์ ์ปฌ๋ผ, ์ปฌ๋ผ1, ์ปฌ๋ผ2, ...
FROM ํ
์ด๋ธ๋ช
) AS ์์ค
UNPIVOT (
๊ฐ์ปฌ๋ผ FOR ๊ธฐ์ค์ปฌ๋ผ IN (์ปฌ๋ผ1, ์ปฌ๋ผ2, ...)
) AS ๊ฒฐ๊ณผ๋ณ์นญ;
Oracle vs MS-SQL ๋ฌธ๋ฒ ์ฐจ์ด์
| ํญ๋ชฉ | ์ค๋ผํด | MS-SQL |
| IN ๋ด๋ถ ๋ณ์นญ | ๊ฐ๋ฅ ('Y2025_07' AS "202507") | ๋ถ๊ฐ๋ฅ (SELECT ์ ์์ AS๋ก ๋ฐ๋ก ์ง์ ) |
| ์๋ธ์ฟผ๋ฆฌ ๋ณ์นญ | ์๋ต ๊ฐ๋ฅ | ํ์ |
| PIVOT ์ ๋ค ๋ณ์นญ | โ๋ถ๊ฐ๋ฅ (์ค๋ฅ) | ํ์ |
| PIVOT ์ ์ง๊ณํจ์ | ํ์ | ํ์ |
| ์ซ์ ๊ฐ ์ปฌ๋ผ๋ช ํ๊ธฐ ๋ฐฉ์ | ํฐ๋ฐ์ดํ ์ฌ์ฉ "202507" | ๋๊ดํธ ์ฌ์ฉ [202507] |
์ง๊ณ ํจ์ ์ข ๋ฅ (Oracle & MS-SQL ๊ณตํต)
| ํจ์๋ช | ์ค๋ช | ๋ฐ์ดํฐ ํ์ |
| SUM( ) | ์ซ์๋ค์ ํฉ๊ณ๋ฅผ ๊ณ์ฐ | ์ซ์ํ๋ง ๊ฐ๋ฅ |
| AVG( ) | ํ๊ท ๊ฐ์ ๊ณ์ฐ | ์ซ์ํ๋ง ๊ฐ๋ฅ |
| MAX( ) | ๊ฐ์ฅ ํฐ ๊ฐ์ ๋ฐํ | ์ซ์, ๋ฌธ์ํ ๋ชจ๋ ๊ฐ๋ฅ (๋ฌธ์์ผ ๊ฒฝ์ฐ ์ฌ์ ์ ๊ธฐ์ค) |
| MIN( ) | ๊ฐ์ฅ ์์ ๊ฐ์ ๋ฐํ | ์ซ์, ๋ฌธ์ํ ๋ชจ๋ ๊ฐ๋ฅ |
| COUNT( ) | ๊ฐ์ ๊ฐ์๋ฅผ ๊ณ์ฐ | ๋ชจ๋ ํ์ ๊ฐ๋ฅ |
| COUNT(DISTINCT ์ปฌ๋ผ) | ์ค๋ณต์ ์ ์ธํ ๊ฐ ๊ฐ์ ๊ณ์ฐ | ๋ชจ๋ ํ์ ๊ฐ๋ฅ |
| LISTAGG( ) | ๋ฌธ์์ด ์ฐ๊ฒฐ (*Oracle : GROUP BY ์ ์ฉ) | ๋ฌธ์ํ (PIVOT์๋ ์ฌ์ฉ ๋ถ๊ฐ) |
| STRING_AGG( ) | ๋ฌธ์์ด ์ฐ๊ฒฐ (*MS-SQL : GROUP BY ์ ์ฉ) | ๋ฌธ์ํ (PIVOT์๋ ์ฌ์ฉ ๋ถ๊ฐ) |
4. ์์๋ฌธ์
โ ๋ฌธ์ 1. ๋ค์ SQL ๋ฌธ์ฅ์์ sal ๊ฐ์ ์ด๋ค ์ด๋ก ์ง๊ณ๋๋๊ฐ?
SELECT *
FROM (SELECT TO_CHAR (hiredate, 'YYYY') AS yyyy,
job,
deptno,
sal
FROM emp)
PIVOT (SUM (sal)
FOR deptno IN (10, 20, 30))
ORDER BY 1, 2;
| 1) ์ ์ฒด 2) yyyy 3) yyyy. job 4) yyyy. job, deptno |
โ ๋ฌธ์ 2. ์๋ S_ENR ํ ์ด๋ธ์์ ๊ฒฐ๊ณผ(Result) ๋ฅผ ๊ตฌํ๋ SQL ๋ฌธ์ฅ์ผ๋ก ์ฌ๋ฐ๋ฅธ ๊ฒ์? (Oracle)
[S_ENR]
STUDENT_ID COURSE SEMESTER
------------------------------
S001 MATH 2025-1
S002 ENGLISH 2025-1
S003 MATH 2025-1
S004 SCIENCE 2025-1
S005 ENGLISH 2025-2
S006 ENGLISH 2025-1
S007 SCIENCE 2025-2
[๊ฒฐ๊ณผ]
SEMESTER MATH ENGLISH SCIENCE
--------------------------------------
2025-1 2 2 1
โ
SELECT *
FROM (
SELECT COURSE, STUDENT_ID
FROM S_ENR
WHERE SEMESTER = '2025-1'
)
PIVOT (
COUNT(*) FOR COURSE IN
('MATH' AS MATH, 'ENGLISH' AS ENGLISH, 'SCIENCE' AS SCIENCE)
)
ORDER BY 1;
โก
SELECT *
FROM (
SELECT SEMESTER, COURSE, STUDENT_ID
FROM S_ENR
)
PIVOT (
COUNT(*) FOR COURSE IN
('MATH' AS MATH, 'ENGLISH' AS ENGLISH, 'SCIENCE' AS SCIENCE)
) AS P;
โข
SELECT *
FROM (
SELECT SEMESTER, COURSE,
FROM S_ENR
WHERE SEMESTER = '2025-1'
)
PIVOT (
COUNT(*) FOR COURSE IN
("MATH" AS MATH, "ENGLISH" AS ENGLISH, "SCIENCE" AS SCIENCE)
);
โฃ
SELECT *
FROM (
SELECT SEMESTER, COURSE
FROM S_ENR
WHERE SEMESTER = '2025-1'
)
PIVOT (
COUNT(*) FOR COURSE IN
('MATH' AS MATH, 'ENGLISH' AS ENGLISH, 'SCIENCE' AS SCIENCE)
)
ORDER BY 1;
[์ ๋ต]
๋ฌธ์ 1 : (3)
ํด์ค: ์ง๊ณ ํจ์์ ์ฌ์ฉํ sal, FOR ์ ์ ์ฌ์ฉํ deptno๋ฅผ ์ ์ธํ yyyy. job์ผ๋ก ์ง๊ณ๋๋ค.
๋ฌธ์ 2 : (4)
ํด์ค:
1๋ฒ โ STUDENT_ID๋ฅผ ํฌํจํ ์ฑ PIVOT์ ์ํํ๊ธฐ ๋๋ฌธ์,๊ฒฐ๊ณผ๋ ํ์๋ณ๋ก ์๊ฐํ ๊ณผ๋ชฉ์ด ๊ฐ๋ก๋ก ๋์ด๋์ด ์ถ๋ ฅ๋จ.
(ํ์ 1๋ช
๋น 1ํ์ฉ ์ถ๋ ฅ๋๋ฉฐ, ํ๊ธฐ ๊ตฌ๋ถ์ ๋ํ๋์ง ์์)

2๋ฒ โ PIVOT ์ ๋ค์ AS ๋ณ์นญ ์ฌ์ฉ → ORA-00933: SQL command not properly ended
3๋ฒ โ IN ์ ์ ์ปฌ๋ผ๋ช ์ ํฐ๋ฐ์ดํ๋ก ๋ฌถ์ → ORA-56901: non-constant expression is not allowed
4๋ฒ โ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ ๋์ด.
COURSE๋ฅผ ๊ธฐ์ค์ผ๋ก PIVOT์ ์ ์ฉํด ๊ณผ๋ชฉ๋ช
์ด ์ด(Column)๋ก ์ ํ๋์ด ํด๋น ๊ณผ๋ชฉ์ ์๊ฐํ ํ์ ์๊ฐ ์ง๊ณ๋์ด ํ์
'MATH' AS MATH์ฒ๋ผ ๋ณ์นญ์ ์ง์ ํ๊ธฐ ๋๋ฌธ์ ์ถ๋ ฅ ์ปฌ๋ผ๋ช
์ ๋ฐ์ดํ ์์ด ๊น๋ํ๊ฒ ๋์ด

'IT์๊ฒฉ์ฆ ๊ณต๋ถ > SQLD ์ด๋ก ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [SQLD] ์ ๊ทํํ์ ์์๋ณด๊ธฐ (+๊ธฐ์ถ๋ฌธ์ ) (2) | 2025.07.28 |
|---|---|
| [SQLD] ๋ถ์ ๋น๊ต์ฐ์ฐ์ <> (๋ฌธ์ ํ์ด/ํด์ค) (0) | 2022.05.16 |
| [SQL ์ ๋ฌธ๊ฐ] ๊ณผ๋ชฉII. ์ 3์ฅ ๊ด๋ฆฌ ๊ตฌ๋ฌธ - ์ฐ์ต๋ฌธ์ (์ด 7๋ฌธ์ ) (1) | 2022.04.22 |
| [SQL ์ ๋ฌธ๊ฐ] ๊ณผ๋ชฉII. ์ 3์ฅ ๊ด๋ฆฌ ๊ตฌ๋ฌธ (0) | 2022.04.21 |
| [SQL ์ ๋ฌธ๊ฐ] ๊ณผ๋ชฉII. ์ 2์ฅ SQL ํ์ฉ - ์ฐ์ต๋ฌธ์ (2) | 2022.04.15 |