Answer

Use conditional aggregation - a SUM(CASE WHEN month = X THEN value END) per month - to turn 12 rows into 12 columns.

Solution

SELECT
  SUM(CASE WHEN MONTH(sale_date) = 1 THEN amount END) AS Jan,
  SUM(CASE WHEN MONTH(sale_date) = 2 THEN amount END) AS Feb,
  SUM(CASE WHEN MONTH(sale_date) = 3 THEN amount END) AS Mar,
  SUM(CASE WHEN MONTH(sale_date) = 4 THEN amount END) AS Apr,
  SUM(CASE WHEN MONTH(sale_date) = 5 THEN amount END) AS May,
  SUM(CASE WHEN MONTH(sale_date) = 6 THEN amount END) AS Jun,
  SUM(CASE WHEN MONTH(sale_date) = 7 THEN amount END) AS Jul,
  SUM(CASE WHEN MONTH(sale_date) = 8 THEN amount END) AS Aug,
  SUM(CASE WHEN MONTH(sale_date) = 9 THEN amount END) AS Sep,
  SUM(CASE WHEN MONTH(sale_date) = 10 THEN amount END) AS Oct,
  SUM(CASE WHEN MONTH(sale_date) = 11 THEN amount END) AS Nov,
  SUM(CASE WHEN MONTH(sale_date) = 12 THEN amount END) AS Dec
FROM Sales;

Step by Step

  1. Each CASE WHEN MONTH(sale_date) = N THEN amount END returns the sale amount only for rows in month N, and NULL for every other row.
  2. Wrapping each in SUM() adds up just that month's non-null values - effectively a mini filtered total per column.
  3. Twelve of these side by side turn 12 rows of monthly data into a single wide row with one column per month.

Alternative Method: Native PIVOT (SQL Server / Some Engines)

SELECT * FROM (
  SELECT MONTH(sale_date) AS mth, amount FROM Sales
) src
PIVOT (
  SUM(amount) FOR mth IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) piv;

Engines with a native PIVOT operator (like SQL Server) can express this more compactly, though the underlying logic - grouping and conditionally summing per category - is identical to the CASE approach, which works on virtually every SQL engine.

Key Exam Traps

  • Missing END defaults to NULL, not 0 - which is exactly what makes SUM() correctly ignore non-matching rows. Adding an explicit ELSE 0 would still work since SUM() treats 0 as 0, but it's unnecessary.
  • Multiple years of data: This query silently merges all years together into one "Jan" total if the data spans more than one year - a WHERE YEAR(sale_date) = 2025 filter is usually needed alongside it for a single year's pivot.
  • Column-per-value pivoting requires knowing the values in advance - this only works cleanly because there are exactly 12 known months; pivoting on an unknown or growing set of categories requires dynamic SQL instead.
Written by Lorens Mishra

Software Engineer Notes Management System Administrator

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.