PIVOT / UNPIVOT(행↔열)
Oracle
-- Turn sales by month into columns
SELECT * FROM (
SELECT month, amount FROM sale
)
PIVOT (SUM(amount) FOR month IN ('Jan' AS jan, 'Feb' AS feb, 'Mar' AS mar));
-- UNPIVOT: turn columns back into rows
SELECT product, month, amount
FROM sale_wide
UNPIVOT (amount FOR month IN (jan AS 'Jan', feb AS 'Feb'));PIVOT은 행의 고유 값을 컬럼으로(크로스 탭), UNPIVOT은 컬럼을 다시 행으로 변환하며, 요약/보고서 테이블에 사용한다. Oracle은 11g부터 내장 PIVOT/UNPIVOT 연산자를 제공한다. 컬럼 목록은 정적이어야 한다(동적 컬럼에는 PIVOT XML이나 코드가 필요).
PostgreSQL
-- The tablefunc extension for crosstab
CREATE EXTENSION IF NOT EXISTS tablefunc;
SELECT * FROM crosstab(
'SELECT product, month, amount FROM sale ORDER BY 1,2'
) AS ct(product text, jan numeric, feb numeric, mar numeric);
-- Without an extension: conditional aggregation
SELECT product,
SUM(amount) FILTER (WHERE month = 'Jan') AS jan,
SUM(amount) FILTER (WHERE month = 'Feb') AS feb
FROM sale GROUP BY product;PostgreSQL에는 내장 PIVOT 연산자가 없다. 두 가지 방법이 있다: tablefunc 확장의 crosstab() 함수, 또는 이식 가능한 조건부 집계(SUM(...) FILTER (WHERE ...) 또는 CASE 사용). FILTER 절은 PostgreSQL 고유의 깔끔한 피벗 기법이다.
MySQL
-- There is no PIVOT; conditional aggregation with manual CASE
SELECT product,
SUM(CASE WHEN month = 'Jan' THEN amount ELSE 0 END) AS jan,
SUM(CASE WHEN month = 'Feb' THEN amount ELSE 0 END) AS feb,
SUM(CASE WHEN month = 'Mar' THEN amount ELSE 0 END) AS mar
FROM sale
GROUP BY product;MySQL/MariaDB에는 PIVOT/UNPIVOT 연산자가 없으며, 크로스 탭은 GROUP BY와 대상 컬럼별 SUM(CASE WHEN ... THEN ... END)로 직접 작성한다. 컬럼이 동적이면 prepared statement로 쿼리를 문자열로 생성한다.
SQL Server
SELECT * FROM (
SELECT product, month, amount FROM sale
) src
PIVOT (
SUM(amount) FOR month IN ([Jan], [Feb], [Mar])
) pvt;
-- Converting back with UNPIVOT is also supportedSQL Server는 2005부터 PIVOT과 UNPIVOT 연산자를 네이티브로 지원한다. PIVOT 컬럼 목록은 대괄호로 묶은 정적 값으로 지정하며, 동적 컬럼에는 동적 SQL로 쿼리를 구성한다. 작은 요약에는 조건부 집계(CASE)가 대안이다.
MongoDB
// PIVOT equivalent: conditional aggregation inside $group
db.sale.aggregate([
{ $group: {
_id: "$product",
jan: { $sum: { $cond: [ { $eq: ["$month", "Jan"] }, "$amount", 0 ] } },
feb: { $sum: { $cond: [ { $eq: ["$month", "Feb"] }, "$amount", 0 ] } }
} }
])MongoDB에는 PIVOT 연산자가 없으며, 크로스 탭은 $group 단계에서 대상 컬럼별 $sum + $cond(조건부 집계)로 구성한다. 반대 방향(UNPIVOT)은 $objectToArray와 $unwind로 필드를 행으로 펼친다.
Redis
# Not applicable: Redis has no pivot/cross tab.Redis에는 행과 열을 회전하는 개념이 없다. 요약/크로스 탭은 애플리케이션 측에서 계산하며, 자주 요청되는 요약은 미리 계산해 Hash 필드(컬럼당 필드 하나)에 저장할 수 있다. RediSearch FT.AGGREGATE로 그룹 집계는 가능하지만 진정한 피벗은 아니다.
Elasticsearch
# Closest equivalent: nested terms aggregations
GET sale/_search
{
"size": 0,
"aggs": { "product": { "terms": { "field": "product" },
"aggs": { "month": { "terms": { "field": "month" },
"aggs": { "total": { "sum": { "field": "amount" } } } } } }
}Elasticsearch에는 PIVOT 연산자가 없다. 크로스 요약은 중첩 terms aggregation(외부 키 / 내부 키)으로 구성하며, 결과는 컬럼이 아닌 중첩 버킷으로 반환되어 클라이언트에서 테이블로 변환한다. transform 작업으로 그룹화된 피벗 유사 대상 인덱스를 생성할 수 있다.