SQL Joins

Combine rows from two or more tables based on a shared column — the foundation of nearly every real-world query, since real data almost never lives in one single table.

What & Why

Real business data is split across related tables. marketing.campaigns stores campaign details while marketing.leads stores lead activity, and a JOIN combines them by matching marketing.leads.campaign_id to marketing.campaigns.id.

The column names do not need to be identical. A foreign key and the primary key it references describe the relationship; similar-looking names alone do not.

See How It Works

BUSINESS QUESTION

Marketing wants campaign names beside lead counts.

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.name,
  COUNT(l.id) AS leads
FROM marketing.campaigns c
JOIN marketing.leads l ON l.campaign_id = c.id
GROUP BY c.name
ORDER BY leads DESC, c.name ASC;
RESULT — exact output from the displayed Queryflo rows
nameleads
Spring Launch2
Finance Retargeting1
Retention Webinar1

The inner join omits Enterprise Search because it has no lead row.

Now You Try

Practice this concept

Marketing wants campaign names with their lead counts. Keep only campaigns that have leads, then order by lead count descending and campaign name ascending.

Available schema
marketing

Prefix tables with marketing.table_name.

nameleads
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