SQL Pivot Data

Turn category rows into side-by-side columns with conditional aggregation.

What & Why

PostgreSQL can pivot a fixed category set with either CASE WHEN inside an aggregate or the aggregate FILTER clause. This lesson uses FILTER because each output column states its variant condition directly.

Every conditional count reads the same experiment group, so the output remains one row per experiment_name while control and alternative metrics become separate columns.

See How It Works

BUSINESS QUESTION

Show control and alternative enrollment and conversion counts as separate columns per experiment.

idexperiment_namevariantuser_idenrolled_atconvertedconverted_at
1Onboarding Copycontrol1012024-01-18 10:00:00+00true2024-01-20 09:30:00+00
2Onboarding Copyshort_copy1022024-01-18 10:05:00+00falseNULL
3Upgrade Promptcontrol1032024-03-15 08:00:00+00true2024-03-18 12:45:00+00
4Upgrade Promptannual_first1042024-03-15 08:04:00+00NULLNULL
EXAMPLE QUERY
SELECT
  experiment_name,
  COUNT(*) FILTER (WHERE variant = 'control') AS control_users,
  COUNT(*) FILTER (WHERE variant <> 'control') AS alternative_users,
  COUNT(*) FILTER (WHERE variant = 'control' AND converted IS TRUE) AS control_conversions,
  COUNT(*) FILTER (WHERE variant <> 'control' AND converted IS TRUE) AS alternative_conversions
FROM product.ab_tests
GROUP BY experiment_name
ORDER BY experiment_name;
RESULT — control and alternative variants pivoted
experiment_namecontrol_usersalternative_userscontrol_conversionsalternative_conversions
Onboarding Copy1110
Upgrade Prompt1110

short_copy and annual_first are counted in the alternative columns because both values differ from control.

This lesson's practice is part of Pro.

Advanced business practice

Sign up free to try it on a real business scenario