PIVOT์ด๋?
PIVOT์ ํ
์ด๋ธ์ ํ(row) ๋ฐ์ดํฐ๋ฅผ ์ด(column)์ผ๋ก ๋ณํํด ๊ฐ๋กํ ์์ฝ ๋ทฐ๋ฅผ ๋ง๋๋ SQL ๋ฌธ๋ฒ์ด๋ค.
์์
์ ํผ๋ฒ ํ
์ด๋ธ๊ณผ ์์ ํ ๊ฐ์ ๊ฐ๋
์ด๋ค. ์ธ๋ก๋ก ์์ธ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ก๋ก ํผ์ณ์ ํ๋์ ๋น๊ตํ๊ธฐ ์ข์ ํํ๋ก ๋ง๋ค์ด์ค๋ค.
๋ฐ๋๋ก ์ด์ ๋ค์ ํ์ผ๋ก ๋๋ฆฌ๋ ๊ฑด UNPIVOT์ด ๋ด๋นํ๋ค.
PIVOT ๋ณํ ๊ตฌ์กฐ

month ์ปฌ๋ผ์ ๊ฐ ๊ฐ(2024-01, 02, 03)์ด ์ด ์ด๋ฆ์ผ๋ก ๋ณํ๋๊ณ , revenue ๊ฐ์ด ๊ฐ ์ ์ ์ฑ์ฐ๋ ๊ตฌ์กฐ์ด๋ค.
์ด๊ฒ์ด PIVOT์ ํต์ฌ ๋ฉ์ปค๋์ฆ์ด๋ค.
PIVOT์ด ํ์ํ ์ด์
๊ฒ์/๋งค์ถ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๋ค ๋ณด๋ฉด ์ด๋ฐ ์ํฉ์ด ์์ฃผ ๋ฐ์ํ๋ค.
- ์๋ณ ๋งค์ถ์ด ์ธ๋ก๋ก ์์ฌ ์๋๋ฐ, ๊ฐ๋ก๋ก ํผ์ณ์ ์๋ณ ๋น๊ต๋ฅผ ํด์ผ ํ ๋
- ์ธ๊ทธ๋จผํธ๋ณ ํญ๋ชฉ ์์น๋ฅผ ํ ํ์ ๋๋ํ ๋๊ณ ๋ณด๊ณ ์๋ฅผ ๋ง๋ค์ด์ผ ํ ๋
- BI ๋์๋ณด๋๋ ๋ณด๊ณ ์ฉ ์ฟผ๋ฆฌ์์ ํฌ๋ก์คํญ ํํ๊ฐ ํ์ํ ๋
๊ธฐ๋ณธ ๋ฌธ๋ฒ ๊ตฌ์กฐ
SELECT *
FROM [ํ
์ด๋ธ๋ช
] ๋๋ [์๋ธ์ฟผ๋ฆฌ]
PIVOT (
์ง๊ณํจ์(์ง๊ณํ _์ปฌ๋ผ) FOR ์ด๋ก_๋ฐ๊ฟ_์ปฌ๋ผ IN ([๊ฐ1], [๊ฐ2], [๊ฐ3])
) AS pvt;
3๊ฐ์ง ํต์ฌ ์์๋ง ๊ธฐ์ตํ๋ฉด ๋๋ค.
- ์ง๊ณํจ์(์ง๊ณํ ์ปฌ๋ผ) : ๊ฐ ์ ์ ๋ค์ด๊ฐ ๊ฐ. SUM, AVG, AOUNT, MAX ๋ฑ์ ์ฌ์ฉํ๋ค.
- FOR ์ด๋ก ๋ฐ๊ฟ ์ปฌ๋ผ : ํ ๊ฐ์ ์ด ์ด๋ฆ์ผ๋ก ๋ฐ๊ฟ ์ปฌ๋ผ์ ์ง์ ํ๋ค.
- IN ([๊ฐ1], [๊ฐ2], ...) : ์๋ก ๋ง๋ค์ด์ง ์ด ์ด๋ฆ ๋ชฉ๋ก์ ์ง์ ๋ช ์ํ๋ค.
๊ธฐ๋ณธ ์ฌ์ฉ ์์
SELECT *
FROM (
SELECT salesClass, month, revenue
FROM sales_data
) AS src
PIVOT (
SUM(revenue) FOR month IN ([2024-01], [2024-02], [2024-03])
) AS pvt;
๊ฒฐ๊ณผ:
| salesClass | 2024-01 | 2024-02 | 2024-03 |
| A | 100 | 150 | 200 |
| B | 80 | 120 | 90 |
- FOR month IN (...) ์์ ๋ค์ด๊ฐ๋ ๊ฐ์ ์ค์ ๋ฐ์ดํฐ์ ์กด์ฌํ๋ month ์ปฌ๋ผ ๊ฐ์ด๋ค.
- ๋๊ดํธ([ ])๋ ํ์ดํ(-) ๊ฐ์ ํน์๋ฌธ์๊ฐ ํฌํจ๋ ์ปฌ๋ผ๋ช ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
PIVOT ์์ฑ ์ ํต์ฌ ๊ท์น
1) ์๋ธ์ฟผ๋ฆฌ์ ํ์ํ ์ปฌ๋ผ๋ง ๋จ๊ฒจ์ผ ํ๋ค.
PIVOT์ ์๋ธ์ฟผ๋ฆฌ์ ์กด์ฌํ๋ ์ปฌ๋ผ ์ค FOR ์ ๊ณผ ์ง๊ณ ๋์ ์ปฌ๋ผ์ ์ ์ธํ ๋๋จธ์ง๋ฅผ ์๋์ผ๋ก GROUP BY ๊ธฐ์ค์ผ๋ก ์ผ๋๋ค.
-- โ ์๋ชป๋ ์ : gameDataId๊ฐ ์์ผ๋ฉด salesClass + gameDataId ์กฐํฉ์ผ๋ก ๊ทธ๋ฃน์ด ๋๋จ
SELECT *
FROM (
SELECT salesClass, gameDataId, month, revenue -- gameDataId๊ฐ ์๋์น ์์ ๊ทธ๋ฃน ๊ธฐ์ค์ด ๋จ
FROM sales_data
) AS src
PIVOT (
SUM(revenue) FOR month IN ([2024-01], [2024-02], [2024-03])
) AS pvt;
-- โ
์ฌ๋ฐ๋ฅธ ์ : ํ์ํ ์ปฌ๋ผ๋ง ๋ช
์
SELECT *
FROM (
SELECT salesClass, month, revenue
FROM sales_data
) AS src
PIVOT (
SUM(revenue) FOR month IN ([2024-01], [2024-02], [2024-03])
) AS pvt;
PIVOT ์ฟผ๋ฆฌ์์ ๊ฐ์ฅ ๋ง์ด ์ค์ํ๋ ๋ถ๋ถ์ด๋ค.
์๋ธ์ฟผ๋ฆฌ์ ์ปฌ๋ผ์ด ๋ง์ผ๋ฉด ๊ฒฐ๊ณผ ํ์ด ์์๋ณด๋ค ๋ง์์ง๋ ์ด์ ๊ฐ ์ฌ๊ธฐ์ ์๋ค.
2) In ์ ์ ๊ฐ์ ๋ฐ๋์ ์ฌ์ ์ ์๊ณ ์์ด์ผ ํ๋ค.
PIVOT์ ๊ฐ์ฅ ํฐ ์ ์ฝ์ IN ์ ์ ๋ค์ด๊ฐ ์ด ๊ฐ์ ์ฟผ๋ฆฌ ์์ฑ ์์ ์ ์ง์ ๋ช ์ํด์ผ ํ๋ค๋ ์ ์ด๋ค.
-- ์ปฌ๋ผ์ด ๊ณ ์ ๋ ๊ฒฝ์ฐ : ์ ์ PIVOT์ผ๋ก ์ถฉ๋ถ
FOR month IN ([2024-01], [2024-02], [2024-03])
-- ์ปฌ๋ผ์ด ๋์ ์ผ๋ก ๋ฐ๋๋ ๊ฒฝ์ฐ : ๋์ PIVOT์ด ํ์ํ๋ค (์๋์์ ์ค๋ช
)
๋์ PIVOT (Dynamic PIVOT)
๋ฐ์ดํฐ์ ๋ฐ๋ผ ์ด ๊ฐ์ด ๋ฌ๋ผ์ง๋ ๊ฒฝ์ฐ, ์ฆ ์ด๋ค ๊ฐ์ด ์ฌ์ง ๋ฏธ๋ฆฌ ์ ์ ์๋ ๊ฒฝ์ฐ์๋ ๋์ ์ผ๋ก SQL์ ์กฐ๋ฆฝํด ์คํํด์ผ ํ๋ค.
DECLARE @cols NVARCHAR(MAX);
DECLARE @sql NVARCHAR(MAX);
-- 1๋จ๊ณ : ์ด๋ก ๋ง๋ค ๊ฐ ๋ชฉ๋ก์ ๋์ ์ผ๋ก ์กฐํ
SELECT @cols = STRING_AGG(QUOTENAME(month), ', ')
WITHIN GROUP (ORDER BY month)
FROM (SELECT DISTINCT month FROM sales_data) AS t;
-- 2๋จ๊ณ : ๋์ SQL ์กฐ๋ฆฝ
SET @sql = N'
SELECT *
FROM (
SELECT salesClass, month, revenue
FROM sales_data
) AS src
PIVOT (
SUM(revenue) FOR month IN (' + @cols + N')
) AS pvt;';
-- 3๋จ๊ณ : ์คํ
EXEC sp_executesql @sql;
UNPIVOT : PIVOT์ ๋ฐ๋
์ด(Column)์ ๋ค์ ํ(Row)๋ก ๋ณํํ ๋ ์ฌ์ฉํ๋ค.
SELECT salesClass, month, revenue
FROM (
SELECT salesClass, [2024-01], [2024-02], [2024-03]
FROM pivot_result
) AS src
UNPIVOT (
revenue FOR month IN ([2024-01], [2024-02], [2024-03])
) AS unpvt;
- PIVOT์ผ๋ก ํผ์น ๋ฐ์ดํฐ๋ฅผ ๋ค์ ์ธ๋ก ํํ๋ก ๋๋๋ฆด ๋ ํ์ฉํ๋ค.
- ETL ํ์ดํ๋ผ์ธ์์ ๊ฐ๋กํ ์๋ณธ ๋ฐ์ดํฐ๋ฅผ ์ธ๋กํ์ผ๋ก ์ ๊ทํํ ๋ ์ ์ฉํ๋ค.
PIVOT vs CASE WHEN ๋น๊ต
PIVOT ์ด์ ์๋ CASE WHEN์ผ๋ก ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์๋ค.
-- CASE WHEN ๋ฐฉ์
SELECT
salesClass,
SUM(CASE WHEN month = '2024-01' THEN revenue ELSE 0 END) AS [2024-01],
SUM(CASE WHEN month = '2024-02' THEN revenue ELSE 0 END) AS [2024-02],
SUM(CASE WHEN month = '2024-03' THEN revenue ELSE 0 END) AS [2024-03]
FROM sales_data
GROUP BY salesClass;
| ๊ตฌ๋ถ | PIVOT | CASE WHEN |
| ๊ฐ๋ ์ฑ | ์ด์ด ๋ง์์๋ก ๊น๋ | ์ด์ด ๋ง์์๋ก ์ฝ๋๊ฐ ๊ธธ์ด์ง |
| ์ ์ฐ์ฑ | IN ์ ๊ฐ ๊ณ ์ ํ์ | ์กฐ๊ฑด์ ์์ ๋กญ๊ฒ ๋ณํ ๊ฐ๋ฅ |
| ๋์ ์ด | ๋์ SQL ํ์ | ๋์ SQL ํ์ |
| ์ฑ๋ฅ | ์ ์ฌ | ์ ์ฌ |
| NULL ์ฒ๋ฆฌ | NULL ๊ทธ๋๋ก ๋ฐํ | ELSE 0์ผ๋ก ์ ์ด ๊ฐ๋ฅ |
- ์ด ์๊ฐ ๋ง๊ณ ๊ณ ์ ๋์ด ์๋ค๋ฉด PIVOT์ด ๋ ๊น๋ํ๋ค.
- NULL์ 0์ผ๋ก ๋ฐ๊พธ๋ ๋ฑ ์ธ๋ถ ์ ์ด๊ฐ ํ์ํ๋ฉด CASE WHEN์ด ์ ๋ฆฌํ๋ค.
NULL ์ฒ๋ฆฌ: PIVOT ๊ฒฐ๊ณผ์ NULL ์ฑ์ฐ๊ธฐ
PIVOT์์ ํด๋น ๊ฐ์ด ์์ผ๋ฉด ์๋์ผ๋ก NULL์ด ๋ค์ด๊ฐ๋ค.
์ด๋ฅผ 0์ด๋ ๋ค๋ฅธ ๊ฐ์ผ๋ก ์ฑ์ฐ๋ ค๋ฉด ISNULL ๋๋ COALSCE๋ก ๊ฐ์ธ์ผ ํ๋ค.
SELECT
salesClass,
ISNULL([2024-01], 0) AS [2024-01],
ISNULL([2024-02], 0) AS [2024-02],
ISNULL([2024-03], 0) AS [2024-03]
FROM (
SELECT salesClass, month, revenue
FROM sales_data
) AS src
PIVOT (
SUM(revenue) FOR month IN ([2024-01], [2024-02], [2024-03])
) AS pvt;
PIVOT ์ฌ์ฉ ์ ์ฃผ์์ฌํญ
โ ์๋ธ์ฟผ๋ฆฌ ์ปฌ๋ผ์ ์ต์ํํ์
- ์ง๊ณ ๊ธฐ์ค, FOR ๋์, ์ง๊ณ ์ปฌ๋ผ ๋ฑ 3๊ฐ์ง๋ง ๋จ๊ฒจ์ผ ์๋ํ ๊ทธ๋ฃนํ์ด ๋๋ค.
โ ๋์ PIVOT์ SQL ์ธ์ ์ ์ ์ฃผ์ํ์
- QUOTENAME()์ ๋ฐ๋์ ์ฌ์ฉํด ์ปฌ๋ผ๋ช ์ ๊ฐ์ธ์ค์ผ ํน์ ๋ฌธ์๋ ์ ์์ ์ธ ์ ๋ ฅ์ ๋ฐฉ์ดํ ์ ์๋ค.
โ NULL์ ๋ฐ๋์ ์ฒ๋ฆฌํ์
- ๋ฐ์ดํฐ๊ฐ ์๋ ์กฐํฉ์ NULL๋ก ์ฑ์์ง๋ค. ์ง๊ณ ๋ชฉ์ ์ด๋ผ๋ฉด ISNULL(์ปฌ๋ผ, 0)์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค.
โ IN ์ ๊ฐ์ ์์๋ ๊ฒฐ๊ณผ ์ด ์์์ ์ํฅ์ ์ค๋ค
- ๋์ PIVOT์์ ORDER BY๋ฅผ ํตํด ์ด ์์๋ฅผ ์ ์ดํ์.
๊ฒฐ๋ก : ํ ์ค ์์ฝ
PIVOT์ ์ธ๋ก๋ก ์์ธ ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ก๋ก ํผ์ณ ํฌ๋ก์คํญ ํํ์ ์์ฝ ๋ทฐ๋ฅผ ๋ง๋๋ MSSQL ๋ฌธ๋ฒ์ผ๋ก, ์๋ธ์ฟผ๋ฆฌ ์ปฌ๋ผ ์ค๊ณ์ ๋์ PIVOT ํจํด๋ง ์ตํ๋ฉด ๋ณด๊ณ ์/๋์๋ณด๋์ฉ ์ฟผ๋ฆฌ๋ฅผ ํจ์ฌ ๊ฐ๊ฒฐํ๊ฒ ์์ฑํ ์ ์๋ค.
References
https://learn.microsoft.com/ko-kr/sql/t-sql/queries/from-using-pivot-and-unpivot
https://learn.microsoft.com/ko-kr/sql/t-sql/functions/string-agg-transact-sql
'๐ฆ MSSQL SQL Server > ๐๏ธ MSSQL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [MSSQL] SQL JOIN ์๋ฒฝ ์ ๋ฆฌ_ํผ์ ์์ง ๋ง๊ณ JOINํ๊ธฐ (1) | 2026.04.19 |
|---|