Learn SQL/Intermediate/Grouping & Aggregation/SQL GROUP BY Multiple Columns

SQL GROUP BY Multiple Columns

List more than one column to group — a new group forms for every distinct COMBINATION of values, not just each column separately.

What & Why

Grouping by one column answers "one number per channel." Sometimes that's not specific enough — "one number per channel, split further by whether the campaign is still active" needs a second grouping column. List both columns, separated by a comma: GROUP BY channel, status.

The important mental model here: Postgres doesn't group by channel and then separately by status — it groups by the unique combination of both values together. Two rows only land in the same group if they match on every listed column, not just one of them. IT-and-active is a different group from IT-and-inactive, even though both share the same channel value.

See How It Works

BUSINESS QUESTION

Marketing wants campaign counts for every channel and status combination.

idnamechannelspendstart_dateend_datestatustarget_segment
1Spring Launchgoogle_ads55000.002024-01-152024-03-31activesmb
2Retention Webinaremail45000.002024-02-102024-04-15activeenterprise
3Finance Retargetinglinkedin50000.002024-03-122024-05-31activeenterprise
4Enterprise Searchgoogle_ads60000.002024-04-012024-06-30activeenterprise
Watch campaign rows enter a channel + status groupCampaign 1 of 4
GROUP BY channel, status · COUNT(*)
idnamechannelstatusgroup keystate
1Spring Launchgoogle_adsactivegoogle_ads · activeCURRENT
2Retention Webinaremailactiveemail · activeWAIT
3Finance Retargetinglinkedinactivelinkedin · activeWAIT
4Enterprise Searchgoogle_adsactivegoogle_ads · activeWAIT
channelstatuscampaign_count
google_adsactive1

Spring Launch contributes to the google_ads · active group; the second google_ads row visibly increments the same bucket.

EXAMPLE QUERY
SELECT
  channel,
  status,
  COUNT(*) AS campaign_count
FROM marketing.campaigns
GROUP BY channel, status
ORDER BY channel, status;
Now You Try

Practice this concept

Marketing wants campaign counts for every channel and status combination.

Available schema
marketing

Prefix tables with marketing.table_name.

channelstatuscampaign_count
marketing.campaigns
ColumnType
idinteger
nametext
channeltext
spendnumeric
start_datedate
end_datedate
statustext
target_segmenttext
legacy_idtext
query.sql
Intermediate business practice

Sign up free to try it on a real business scenario