How to Pivot in SQL
Use pivoting when row values should become separate columns in the result. This is perfect for reporting tables, dashboards, monthly summaries, and cross-tab style exports.
What you’ll build or solve
You’ll learn how to pivot in SQL using conditional aggregation, which works across most database systems. You’ll also know when native PIVOT syntax may be available.
Learn SQL on Mimo
When this approach works best
This approach is the right choice when categories should display side by side as columns.
Common real-world scenarios include:
- Revenue by month
- Scores by subject
- Orders by status columns
- Sales by country
- KPI dashboard tables
This is a bad idea when categories are dynamic and unknown at query-writing time without dynamic SQL.
Prerequisites
You only need:
- Basic
GROUP BY - Familiarity with
CASE - A column that contains category values
Step-by-step instructions
Step 1: Use conditional aggregation
The most portable pivot pattern uses SUM(CASE ...).
SQL
SELECT
country,
SUM(CASE WHEN month = 'Jan' THEN revenue ELSE 0 END) AS jan,
SUM(CASE WHEN month = 'Feb' THEN revenue ELSE 0 END) AS feb,
SUM(CASE WHEN month = 'Mar' THEN revenue ELSE 0 END) AS mar
FROM sales
GROUP BY country;
This turns month rows into columns.
Each CASE branch fills one output column.
This works in PostgreSQL, MySQL, SQL Server, and most other engines.
What to look for:
CASEcreates one column per categoryGROUP BYdefines the row dimension- Great for dashboards and exports
- Works across most databases
- Dynamic categories need dynamic SQL
Examples you can copy
Orders by status
SQL
SELECT
user_id,
SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) AS paid_orders,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending_orders
FROM orders
GROUP BY user_id;
Scores by subject
SQL
SELECT
student_id,
MAX(CASE WHEN subject = 'Math' THEN score END) AS math_score,
MAX(CASE WHEN subject = 'Science' THEN score END) AS science_score
FROM exams
GROUP BY student_id;
Revenue by region
SQL
SELECT
year,
SUM(CASE WHEN region = 'USA' THEN total ELSE 0 END) AS usa_total,
SUM(CASE WHEN region = 'UK' THEN total ELSE 0 END) AS uk_total
FROM revenue
GROUP BY year;
Common mistakes and how to fix them
Mistake 1: Forgetting the grouping dimension
What the reader might do:
SQL
SELECT
SUM(CASE ...)
FROM sales;
Why it breaks: all rows collapse into one giant pivot row.
Corrected approach:
Add the row dimension in GROUP BY.
Mistake 2: Using dynamic categories as static columns
What the reader might do:
Hardcode categories that change every week.
Why it breaks: the query becomes brittle.
Corrected approach:
Use dynamic SQL or pivot in the BI layer.
Mistake 3: Wrong aggregate choice
What the reader might do:
SQL
SUM(CASE WHEN subject = 'Math' THEN score END)
Why it breaks: repeated rows may inflate values when only one score should exist.
Corrected approach:
Use MAX() for single-value cells.
Troubleshooting
If all data lands in one row, add GROUP BY.
If values are inflated, choose the correct aggregate.
If categories change often, use dynamic SQL.
If the database supports native PIVOT, compare readability.
Quick recap
- Pivot rows into columns with
SUM(CASE ...) - Use
GROUP BYfor row dimensions - Pick the correct aggregate
- Great for reports and dashboards
- Use dynamic SQL for changing categories
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot