Learn SQL/Intermediate/Joins/SQL Multiple JOINs

SQL Multiple JOINs

Chain more than one JOIN in a single query — each new JOIN builds on the combined result of everything before it, not on the original table alone.

What & Why

Each additional JOIN connects another table to the result assembled so far. The Queryflo example starts from saas.accounts, then attaches saas.invoices and saas.seats; because both child tables are one-to-many, their rows can multiply each other before aggregation.

See How It Works

BUSINESS QUESTION

SaaS leadership wants invoice and seat counts beside every account.

idnameplanmrrcreated_atchurned_atcountryemployee_countindustry
1Acme Labsgrowth240.002024-01-08 10:00:00+00NULLUS45software
2Northstar Costarter90.002024-02-12 09:30:00+002024-05-18 12:00:00+00CA18services
3Atlas Worksscale480.002024-03-04 15:10:00+00NULLGB120manufacturing
4Bright Pathgrowth180.002024-04-19 11:45:00+00NULLUS62education
idaccount_idamountstatusdue_datepaid_at
101240.00paid2024-02-012024-01-29 13:00:00+00
111260.00paid2024-03-012024-02-28 16:30:00+00
12290.00overdue2024-03-15NULL
133480.00open2024-04-01NULL
idaccount_iduser_emailrolecreated_atlast_active_at
201owner@acme.testowner2024-01-08 10:10:00+002024-04-10 08:30:00+00
211analyst@acme.testmember2024-01-10 14:00:00+002024-04-09 16:20:00+00
222owner@northstar.testowner2024-02-12 09:40:00+002024-04-02 10:00:00+00
233admin@atlas.testadmin2024-03-04 15:20:00+002024-04-11 12:15:00+00
Trace the relationship row by row1× speed
saas.accounts
idname
1Acme Labs
2Northstar Co
3Atlas Works
4Bright Path
TWO LEFT JOINS
saas.invoices
idaccount_idamountstatus
101240.00paid
111260.00paid
12290.00overdue
133480.00open
saas.seats
idaccount_iduser_emailrole
201owner@acme.testowner
211analyst@acme.testmember
222owner@northstar.testowner
233admin@atlas.testadmin
Result set · 1 rows
nameinvoice_countseat_count
Acme Labs22

Acme's two invoices and two seats create four intermediate combinations; both DISTINCT counts remain two.

EXAMPLE QUERY
SELECT
  a.name,
  COUNT(DISTINCT i.id) AS invoice_count,
  COUNT(DISTINCT s.id) AS seat_count
FROM saas.accounts a
LEFT JOIN saas.invoices i ON i.account_id = a.id
LEFT JOIN saas.seats s ON s.account_id = a.id
GROUP BY a.id, a.name
ORDER BY a.name;
Now You Try

Practice this concept

SaaS leadership wants invoice and seat counts beside every account.

Available schema
saas

Prefix tables with saas.table_name.

nameinvoice_countseat_count
saas.accounts
ColumnType
idinteger
nametext
plantext
mrrnumeric
created_attimestamp with time zone
churned_attimestamp with time zone
countrytext
employee_countinteger
industrytext
customer_segment_v2text
saas.invoices
ColumnType
idinteger
account_idinteger
amountnumeric
statustext
due_datedate
paid_attimestamp with time zone
internal_invoice_batchtext
saas.seats
ColumnType
idinteger
account_idinteger
user_emailtext
roletext
created_attimestamp with time zone
last_active_attimestamp with time zone
internal_seat_grouptext
query.sql
Intermediate business practice

Sign up free to try it on a real business scenario