Skip to the solution
HardDSA14 min read

How do you pivot rows into columns?

651 views

The problem

Question presented to candidate: "Our sales table has one row per sale with a region, a quarter and an amount. Finance wants a report with one row per region and one column per quarter, Q1 to Q4, holding the total. Write that query. Then tell me what you would do if the list of quarters is not known in advance, and how the answer differs between PostgreSQL, SQL Server and SQLite."

What a strong answer should cover:

  • Pivoting turns the distinct values of one column into output columns; the portable way is conditional aggregation: GROUP BY the row key and one SUM(CASE WHEN quarter = 'Q1' THEN amount END) per column
  • Empty cells: without ELSE the cell is NULL, with ELSE 0 or COALESCE it is 0; choose deliberately, and make COUNT versus SUM behave right
  • The FILTER (WHERE ...) clause (PostgreSQL, SQLite 3.30+) as a cleaner spelling of the same thing
  • Engine features: SQL Server and Oracle PIVOT, PostgreSQL crosstab() from the tablefunc extension; all need the column list written out
  • SQL needs the output columns at parse time, so a pivot over unknown values needs dynamic SQL generated from the data (or pivoting in the application); and the reverse, unpivot, with UNION ALL or UNPIVOT

Clarifying questions expected:

  • Is the set of pivot values fixed (four quarters) or does it grow with the data?
  • Should a missing combination show 0 or be empty?
  • Is the result for a human report (pivot in SQL or the BI tool) or for code (keep it long)?

Code / implementation expected: Yes β€” a conditional-aggregation pivot query; optionally the dynamic-SQL generator.

Schema used by the examples:

  • pivot

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

14 min read Β· 13 sections

Run the code

Edit the query and run it against the tables for this question.

SQLConditional aggregation: one SUM(CASE ...) per quarter, NULL vs ELSE 0, plus a total
SQLThe FILTER clause: counts and half-year sums per region (SQLite 3.30+ and PostgreSQL)
PostgreSQL crosstab() from the tablefunc extension
CREATE EXTENSION IF NOT EXISTS tablefunc;

SELECT *
FROM crosstab(
  $$SELECT region, quarter, SUM(amount)::int
    FROM sales GROUP BY region, quarter ORDER BY 1, 2$$,
  $$VALUES ('Q1'), ('Q2'), ('Q3'), ('Q4')$$
) AS ct(region text, q1 int, q2 int, q3 int, q4 int)
ORDER BY region;
SQLDynamic pivot: build the SELECT from the distinct quarters in the data

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 74 of 82 in SQL

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All SQL questions
Up nextHard

Why does column order matter in a composite index?

Continue