SQL Advanced

How to Pivot a Table in SQL (MySQL, PostgreSQL, SQL Server)

Learn how to pivot rows to columns in SQL. Covers CASE WHEN pivot, PIVOT operator (SQL Server), crosstab (PostgreSQL), and dynamic pivots.

Mar 12, 2026 7 min read

Introduction

Pivoting transforms rows into columns — turning vertical data into a horizontal summary table. Every database handles this differently, so knowing the right syntax for your database is essential.

Pivot with CASE WHEN (Works in All Databases)

The universal approach that works in MySQL, PostgreSQL, SQL Server, SQLite, and Oracle. Use CASE inside aggregate functions.

-- Sample data: sales by quarter
-- | product | quarter | revenue |
-- | Widget  | Q1      | 1000    |
-- | Widget  | Q2      | 1500    |
-- | Gadget  | Q1      | 800     |

-- Pivot: quarters become columns
SELECT
  product,
  SUM(CASE WHEN quarter = 'Q1' THEN revenue ELSE 0 END) AS Q1,
  SUM(CASE WHEN quarter = 'Q2' THEN revenue ELSE 0 END) AS Q2,
  SUM(CASE WHEN quarter = 'Q3' THEN revenue ELSE 0 END) AS Q3,
  SUM(CASE WHEN quarter = 'Q4' THEN revenue ELSE 0 END) AS Q4
FROM sales
GROUP BY product;

Tip: This is the most portable approach. Use SUM for numbers, MAX for strings.

Pivot in SQL Server (PIVOT Operator)

SQL Server has a native PIVOT operator that makes the syntax more declarative.

-- SQL Server PIVOT syntax:
SELECT product, [Q1], [Q2], [Q3], [Q4]
FROM (
  SELECT product, quarter, revenue
  FROM sales
) AS source
PIVOT (
  SUM(revenue)
  FOR quarter IN ([Q1], [Q2], [Q3], [Q4])
) AS pivot_table;

Tip: Square brackets are required around the pivot values. The values must be known at query time.

Pivot in PostgreSQL (crosstab)

PostgreSQL uses the crosstab() function from the tablefunc extension.

-- Enable the extension first:
CREATE EXTENSION IF NOT EXISTS tablefunc;

-- Crosstab pivot:
SELECT * FROM crosstab(
  'SELECT product, quarter, revenue
   FROM sales
   ORDER BY 1, 2',
  $$VALUES ('Q1'), ('Q2'), ('Q3'), ('Q4')$$
) AS ct(product TEXT, q1 INT, q2 INT, q3 INT, q4 INT);

Tip: The CASE WHEN approach often works better in PostgreSQL for simple pivots. Use crosstab when you need more control.

Pivot with COUNT (Frequency Tables)

Pivoting counts instead of sums — useful for frequency analysis and cross-tabulation.

-- Count users by country and plan:
SELECT
  country,
  COUNT(CASE WHEN plan = 'free' THEN 1 END) AS free_users,
  COUNT(CASE WHEN plan = 'pro' THEN 1 END) AS pro_users,
  COUNT(CASE WHEN plan = 'enterprise' THEN 1 END) AS enterprise_users,
  COUNT(*) AS total
FROM users
GROUP BY country
ORDER BY total DESC;

Tip: Use COUNT(CASE WHEN ... THEN 1 END) instead of SUM for counting. The THEN value doesn't matter — COUNT ignores NULLs.

Unpivot: Columns Back to Rows

The reverse of pivot — turn columns into rows using UNION ALL or UNPIVOT.

-- Universal unpivot with UNION ALL:
SELECT product, 'Q1' AS quarter, q1 AS revenue FROM sales_pivot
UNION ALL
SELECT product, 'Q2', q2 FROM sales_pivot
UNION ALL
SELECT product, 'Q3', q3 FROM sales_pivot
UNION ALL
SELECT product, 'Q4', q4 FROM sales_pivot;

-- SQL Server UNPIVOT:
SELECT product, quarter, revenue
FROM sales_pivot
UNPIVOT (revenue FOR quarter IN (Q1, Q2, Q3, Q4)) AS unpvt;

Tip: UNION ALL is the most portable unpivot method. SQL Server's UNPIVOT is cleaner but SQL Server only.

Best Practices

  • Start with the CASE WHEN approach — it works everywhere
  • Make sure your GROUP BY includes all non-aggregated columns
  • For dynamic pivots (unknown column values), use dynamic SQL or application code
  • Test with a small dataset first to verify the pivot logic
  • Use aliases to make pivot column names readable

Generate SQL Queries with AI2SQL

Skip the syntax lookup. Describe what you need in plain English and AI2SQL generates the correct SQL query instantly.

Try AI2SQL Free

No credit card required

Frequently Asked Questions

How do I pivot rows to columns in SQL?

Use SUM(CASE WHEN column = value THEN amount ELSE 0 END) with GROUP BY. This works in all databases. SQL Server also has a native PIVOT operator.

Can I pivot with dynamic/unknown values?

Not directly in standard SQL — pivot values must be known at query time. Use dynamic SQL (stored procedure) or generate the query in your application code.

Can AI2SQL generate pivot queries?

Yes. Tell AI2SQL "pivot sales by quarter with product as rows" and it generates the correct pivot query for your database dialect.

Generate SQL from Plain English

Stop memorizing syntax. Describe what you need and let AI2SQL write the query for you.

Try AI2SQL Free

No credit card required