lesson 25 Joins & sets · intermediate
ON versus WHERE in a LEFT JOIN
Place filters carefully when preserving unmatched rows.
the idea
In a LEFT JOIN, a condition in ON decides which right-side rows match; unmatched left rows are still kept. The same condition in WHERE runs after the join and removes rows whose right side is NULL, turning the LEFT JOIN back into an inner join.
Dataset: Healthcare
The tables the challenges use, with their first 6 rows. Under each column name: the kind of value it holds, and which table it links to.
providers6 columns · 460 rows
| provider_idnumber · unique id | full_nametext | specialtytext | clinic_nametext | citytext | statetext |
|---|---|---|---|---|---|
| 1 | Amara Mehta | Family Medicine | Providence Family Practice | Providence | RI |
| 2 | Alice Hill | Family Medicine | Nimbus Health Center | Atlanta | GA |
| 3 | Ryan Shah | Nephrology | Cleveland Community Clinic | Cleveland | OH |
| 4 | Sofia Lee | Family Medicine | Albuquerque Community Clinic | Albuquerque | NM |
| 5 | Joseph Howard | Family Medicine | Prism Health Center | New York | NY |
| 6 | Anika Scott | Pediatrics | Solar Health Center | Indianapolis | IN |
- provider_idnumber · unique id
- 1
- full_nametext
- Amara Mehta
- specialtytext
- Family Medicine
- clinic_nametext
- Providence Family Practice
- citytext
- Providence
- statetext
- RI
- provider_idnumber · unique id
- 2
- full_nametext
- Alice Hill
- specialtytext
- Family Medicine
- clinic_nametext
- Nimbus Health Center
- citytext
- Atlanta
- statetext
- GA
- provider_idnumber · unique id
- 3
- full_nametext
- Ryan Shah
- specialtytext
- Nephrology
- clinic_nametext
- Cleveland Community Clinic
- citytext
- Cleveland
- statetext
- OH
- provider_idnumber · unique id
- 4
- full_nametext
- Sofia Lee
- specialtytext
- Family Medicine
- clinic_nametext
- Albuquerque Community Clinic
- citytext
- Albuquerque
- statetext
- NM
- provider_idnumber · unique id
- 5
- full_nametext
- Joseph Howard
- specialtytext
- Family Medicine
- clinic_nametext
- Prism Health Center
- citytext
- New York
- statetext
- NY
- provider_idnumber · unique id
- 6
- full_nametext
- Anika Scott
- specialtytext
- Pediatrics
- clinic_nametext
- Solar Health Center
- citytext
- Indianapolis
- statetext
- IN
first 6 of 460 rows · your queries use all of them
encounters9 columns · 20,447 rows
| encounter_idnumber · unique id | patient_idnumber · links to patients | provider_idnumber · links to providers | encounter_classtext | start_atdate & time | end_atdate & time | reason_codetext | total_costdecimal | payer_paiddecimal |
|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 4 | ambulatory | 2022-08-07 13:00:00 | 2022-08-07 13:24:45 | T78.40XA | 175.6 | 159.38 |
| 2 | 1 | 4 | telehealth | 2022-10-12 11:15:00 | 2022-10-12 11:59:48 | E11.9 | 110.02 | 95.53 |
| 3 | 1 | 74 | telehealth | 2023-05-12 11:30:00 | 2023-05-12 12:13:27 | E11.9 | 83.68 | 74.77 |
| 4 | 1 | 349 | ambulatory | 2023-12-17 08:15:00 | 2023-12-17 08:39:33 | E11.9 | 198.23 | 187.3 |
| 5 | 1 | 4 | telehealth | 2024-05-09 16:45:00 | 2024-05-09 17:29:01 | E66.9 | 115.08 | 98.4 |
| 6 | 1 | 4 | ambulatory | 2024-09-07 13:00:00 | 2024-09-07 13:27:30 | E66.9 | 153.61 | 142.99 |
- encounter_idnumber · unique id
- 1
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 4
- encounter_classtext
- ambulatory
- start_atdate & time
- 2022-08-07 13:00:00
- end_atdate & time
- 2022-08-07 13:24:45
- reason_codetext
- T78.40XA
- total_costdecimal
- 175.6
- payer_paiddecimal
- 159.38
- encounter_idnumber · unique id
- 2
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 4
- encounter_classtext
- telehealth
- start_atdate & time
- 2022-10-12 11:15:00
- end_atdate & time
- 2022-10-12 11:59:48
- reason_codetext
- E11.9
- total_costdecimal
- 110.02
- payer_paiddecimal
- 95.53
- encounter_idnumber · unique id
- 3
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 74
- encounter_classtext
- telehealth
- start_atdate & time
- 2023-05-12 11:30:00
- end_atdate & time
- 2023-05-12 12:13:27
- reason_codetext
- E11.9
- total_costdecimal
- 83.68
- payer_paiddecimal
- 74.77
- encounter_idnumber · unique id
- 4
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 349
- encounter_classtext
- ambulatory
- start_atdate & time
- 2023-12-17 08:15:00
- end_atdate & time
- 2023-12-17 08:39:33
- reason_codetext
- E11.9
- total_costdecimal
- 198.23
- payer_paiddecimal
- 187.3
- encounter_idnumber · unique id
- 5
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 4
- encounter_classtext
- telehealth
- start_atdate & time
- 2024-05-09 16:45:00
- end_atdate & time
- 2024-05-09 17:29:01
- reason_codetext
- E66.9
- total_costdecimal
- 115.08
- payer_paiddecimal
- 98.4
- encounter_idnumber · unique id
- 6
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 4
- encounter_classtext
- ambulatory
- start_atdate & time
- 2024-09-07 13:00:00
- end_atdate & time
- 2024-09-07 13:27:30
- reason_codetext
- E66.9
- total_costdecimal
- 153.61
- payer_paiddecimal
- 142.99
first 6 of 20,447 rows · your queries use all of them
patients9 columns · 3,200 rows
| patient_idnumber · unique id | first_nametext | last_nametext | sextext | birth_datedate | citytext | statetext | insurance_typetext | deceased_datetext |
|---|---|---|---|---|---|---|---|---|
| 1 | Sara | Foster | M | 1972-05-08 | Baltimore | MD | medicaid | NULL |
| 2 | Anika | Jackson | M | 1953-07-10 | Baltimore | MD | medicare | NULL |
| 3 | Jessica | Hughes | F | 2010-12-24 | Newark | NJ | medicaid | NULL |
| 4 | Rahul | Gonzalez | F | 2023-04-04 | Los Angeles | CA | commercial | NULL |
| 5 | Jasmine | Miller | M | 1996-08-07 | Manchester | NH | medicaid | NULL |
| 6 | Emma | Ibrahim | M | 1933-12-10 | New York | NY | medicare | NULL |
- patient_idnumber · unique id
- 1
- first_nametext
- Sara
- last_nametext
- Foster
- sextext
- M
- birth_datedate
- 1972-05-08
- citytext
- Baltimore
- statetext
- MD
- insurance_typetext
- medicaid
- deceased_datetext
- NULL
- patient_idnumber · unique id
- 2
- first_nametext
- Anika
- last_nametext
- Jackson
- sextext
- M
- birth_datedate
- 1953-07-10
- citytext
- Baltimore
- statetext
- MD
- insurance_typetext
- medicare
- deceased_datetext
- NULL
- patient_idnumber · unique id
- 3
- first_nametext
- Jessica
- last_nametext
- Hughes
- sextext
- F
- birth_datedate
- 2010-12-24
- citytext
- Newark
- statetext
- NJ
- insurance_typetext
- medicaid
- deceased_datetext
- NULL
- patient_idnumber · unique id
- 4
- first_nametext
- Rahul
- last_nametext
- Gonzalez
- sextext
- F
- birth_datedate
- 2023-04-04
- citytext
- Los Angeles
- statetext
- CA
- insurance_typetext
- commercial
- deceased_datetext
- NULL
- patient_idnumber · unique id
- 5
- first_nametext
- Jasmine
- last_nametext
- Miller
- sextext
- M
- birth_datedate
- 1996-08-07
- citytext
- Manchester
- statetext
- NH
- insurance_typetext
- medicaid
- deceased_datetext
- NULL
- patient_idnumber · unique id
- 6
- first_nametext
- Emma
- last_nametext
- Ibrahim
- sextext
- M
- birth_datedate
- 1933-12-10
- citytext
- New York
- statetext
- NY
- insurance_typetext
- medicare
- deceased_datetext
- NULL
first 6 of 3,200 rows · your queries use all of them
appointments7 columns · 19,438 rows
| appointment_idnumber · unique id | patient_idnumber · links to patients | provider_idnumber · links to providers | booked_atdate & time | scheduled_startdate & time | statustext | encounter_idnumber · links to encounters |
|---|---|---|---|---|---|---|
| 1 | 1 | 4 | 2022-08-04 10:00:00 | 2022-08-04 13:00:00 | cancelled | NULL |
| 2 | 1 | 4 | 2022-08-04 10:00:00 | 2022-08-07 13:00:00 | completed | 1 |
| 3 | 1 | 4 | 2022-09-29 09:15:00 | 2022-10-12 11:15:00 | completed | 2 |
| 4 | 1 | 74 | 2023-04-10 06:30:00 | 2023-05-12 11:30:00 | completed | 3 |
| 5 | 1 | 349 | 2023-12-08 05:15:00 | 2023-12-17 08:15:00 | completed | 4 |
| 6 | 1 | 4 | 2024-04-22 12:45:00 | 2024-05-09 16:45:00 | completed | 5 |
- appointment_idnumber · unique id
- 1
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 4
- booked_atdate & time
- 2022-08-04 10:00:00
- scheduled_startdate & time
- 2022-08-04 13:00:00
- statustext
- cancelled
- encounter_idnumber · links to encounters
- NULL
- appointment_idnumber · unique id
- 2
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 4
- booked_atdate & time
- 2022-08-04 10:00:00
- scheduled_startdate & time
- 2022-08-07 13:00:00
- statustext
- completed
- encounter_idnumber · links to encounters
- 1
- appointment_idnumber · unique id
- 3
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 4
- booked_atdate & time
- 2022-09-29 09:15:00
- scheduled_startdate & time
- 2022-10-12 11:15:00
- statustext
- completed
- encounter_idnumber · links to encounters
- 2
- appointment_idnumber · unique id
- 4
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 74
- booked_atdate & time
- 2023-04-10 06:30:00
- scheduled_startdate & time
- 2023-05-12 11:30:00
- statustext
- completed
- encounter_idnumber · links to encounters
- 3
- appointment_idnumber · unique id
- 5
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 349
- booked_atdate & time
- 2023-12-08 05:15:00
- scheduled_startdate & time
- 2023-12-17 08:15:00
- statustext
- completed
- encounter_idnumber · links to encounters
- 4
- appointment_idnumber · unique id
- 6
- patient_idnumber · links to patients
- 1
- provider_idnumber · links to providers
- 4
- booked_atdate & time
- 2024-04-22 12:45:00
- scheduled_startdate & time
- 2024-05-09 16:45:00
- statustext
- completed
- encounter_idnumber · links to encounters
- 5
first 6 of 19,438 rows · your queries use all of them
worked example
Run these steps in order to see the idea before you write your own query. The step marked “the pattern” is what the challenges ask for. Running the example does not count toward progress.
Put the filter in ON. Run this. LEFT JOIN with telehealth in ON keeps every provider; counts are zero when none match.
step-1.sqlSELECT p.provider_id, COUNT(e.encounter_id) AS telehealth_visits FROM providers p LEFT JOIN encounters e ON e.provider_id = p.provider_id AND e.encounter_class = 'telehealth' GROUP BY p.provider_id ORDER BY telehealth_visits LIMIT 10;
Same filter in WHERE instead. Run this. WHERE telehealth removes providers with no matching encounter—like an inner join.
step-2.sqlSELECT COUNT(DISTINCT p.provider_id) AS providers_left FROM providers p LEFT JOIN encounters e ON e.provider_id = p.provider_id WHERE e.encounter_class = 'telehealth';
Put it together. The lesson's pattern in one query.the pattern
example.sqlSELECT p.provider_id, COUNT(e.encounter_id) AS telehealth_visits FROM providers p LEFT JOIN encounters e ON e.provider_id = p.provider_id AND e.encounter_class = 'telehealth' GROUP BY p.provider_id;
common mistake
LEFT JOIN encounters e ON … WHERE e.encounter_class = 'emergency' drops every provider without an emergency visit.