SQL NULL in JOINs

A LEFT JOIN fills in NULL for every column on the unmatched side — the same mechanism covered in the Joins series, revisited here as a NULL-specific concept.

What & Why

When a LEFT JOIN finds no match for a row, every column that would have come from the right table becomes NULL — not just one column, all of them. This is exactly the same behavior the Joins series covered, worth reinforcing here as a direct application of what NULL actually means: "no matching data exists."

See How It Works

BUSINESS QUESTION

Marketing wants every campaign plus its lead count, including campaigns with no leads.

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
idcampaign_idemailcreated_atqualified_atconverted_atlead_scoresourcecountry
3011ana@example.com2024-01-21 09:10:00+002024-01-22 11:00:00+002024-02-02 10:00:00+0086google_adsUS
3021ben@example.com2024-01-24 12:40:00+00NULLNULL52google_adsCA
3032chloe@example.com2024-02-16 08:30:00+002024-02-18 14:20:00+00NULL74emailGB
3043dev@example.com2024-03-20 17:15:00+002024-03-21 09:00:00+002024-04-04 16:00:00+0091linkedinUS
EXAMPLE QUERY
SELECT
  c.id AS campaign_id,
  c.name,
  COUNT(l.id) AS lead_count
FROM marketing.campaigns c
LEFT JOIN marketing.leads l ON l.campaign_id = c.id
GROUP BY c.id, c.name
ORDER BY campaign_id;
RESULT — exact output from the displayed Queryflo rows
campaign_idnamelead_count
1Spring Launch2
2Retention Webinar1
3Finance Retargeting1
4Enterprise Search0

The unmatched campaign remains and COUNT(l.id) correctly returns zero.

Now You Try

Practice this concept

Marketing wants every campaign and its lead count, including campaigns that have no matching leads.

Available schema
marketing

Prefix tables with marketing.table_name.

campaign_idnamelead_count
marketing.campaigns
ColumnType
idinteger
nametext
channeltext
spendnumeric
start_datedate
end_datedate
statustext
target_segmenttext
legacy_idtext
marketing.leads
ColumnType
idinteger
campaign_idinteger
emailtext
created_attimestamp with time zone
qualified_attimestamp with time zone
converted_attimestamp with time zone
lead_scoreinteger
sourcetext
countrytext
archive_statustext
query.sql
Intermediate business practice

Sign up free to try it on a real business scenario