Healthcare runs on data: admissions, diagnoses, claims, prescriptions. Analysts who can turn those records into accurate measures, such as readmission rates, lengths of stay and cost per patient, help hospitals, insurers and health-tech companies make better decisions, provided they handle patient data with care.
This path teaches SQL on the shape of real healthcare data: patients, encounters, diagnoses, procedures, claims and prescriptions. You'll build patient cohorts from diagnosis codes, calculate length of stay and 30-day readmissions, compare providers fairly, measure medication adherence, and learn the privacy habits that are non-negotiable when you work with health information. Example tables are simplified and fictional; real systems add many more columns, but the patterns are the same.
Most healthcare datasets revolve around a few core tables: patients, encounters (each visit or admission), diagnoses and procedures attached to encounters, claims for what was billed and paid, and prescriptions. One patient has many encounters, and one encounter has many diagnoses, so knowing the grain of each table prevents double counting.
SELECT e.encounter_id, p.patient_id, e.encounter_type,
e.admit_date, e.discharge_date, d.diagnosis_code, d.is_primary
FROM encounters e
JOIN patients p ON p.patient_id = e.patient_id
JOIN diagnoses d ON d.encounter_id = e.encounter_id
WHERE e.admit_date >= '2026-01-01';
DISTINCT encounter_id, or filter to the primary diagnosis, before summing anything per encounter.Conditions are recorded as codes, most commonly ICD-10 for diagnoses. Codes are hierarchical: every code starting with E11 is a form of type 2 diabetes. Match code families with LIKE or, better, a maintained code-group lookup table, so the definition of "diabetic patient" lives in one place.
SELECT DISTINCT e.patient_id
FROM diagnoses d
JOIN encounters e ON e.encounter_id = d.encounter_id
WHERE d.diagnosis_code LIKE 'E11%' -- type 2 diabetes family
AND e.admit_date >= '2025-10-01';
E11.9 and E119 won't match each other, and inconsistent formatting quietly shrinks cohorts.A cohort is a precisely defined group of patients: "adults aged 40-65 with a type 2 diabetes diagnosis and at least two outpatient visits in the past year". Build it step by step with CTEs, one criterion each, so the definition is auditable and the count at each step can be reported.
WITH diabetic AS (
SELECT DISTINCT e.patient_id
FROM diagnoses d JOIN encounters e ON e.encounter_id = d.encounter_id
WHERE d.diagnosis_code LIKE 'E11%'
),
adults AS (
SELECT patient_id FROM patients
WHERE birth_date BETWEEN '1961-01-01' AND '1986-12-31'
),
frequent AS (
SELECT patient_id FROM encounters
WHERE encounter_type = 'outpatient' AND admit_date >= '2025-10-01'
GROUP BY patient_id HAVING COUNT(*) >= 2
)
SELECT COUNT(*) AS cohort_size
FROM diabetic
JOIN adults USING (patient_id)
JOIN frequent USING (patient_id);
Length of stay (LOS) is the number of days between admission and discharge for inpatient encounters. Average LOS by department or diagnosis is a core operational metric. Exclude encounters still in progress (no discharge date) and decide explicitly how same-day discharges count.
SELECT department,
COUNT(*) AS admissions,
ROUND(AVG(discharge_date - admit_date), 1) AS avg_los_days
FROM encounters
WHERE encounter_type = 'inpatient'
AND discharge_date IS NOT NULL
GROUP BY department
ORDER BY avg_los_days DESC;
A readmission is an inpatient admission within 30 days of a previous discharge for the same patient, one of the most-watched quality measures in healthcare. LEAD() finds each patient's next admission in a single pass, without a self-join.
WITH stays AS (
SELECT patient_id, encounter_id, admit_date, discharge_date,
LEAD(admit_date) OVER (PARTITION BY patient_id ORDER BY admit_date) AS next_admit
FROM encounters
WHERE encounter_type = 'inpatient' AND discharge_date IS NOT NULL
)
SELECT COUNT(*) AS discharges,
SUM(CASE WHEN next_admit - discharge_date <= 30 THEN 1 ELSE 0 END) AS readmissions_30d,
ROUND(100.0 * SUM(CASE WHEN next_admit - discharge_date <= 30 THEN 1 ELSE 0 END) / COUNT(*), 1) AS readmission_rate_pct
FROM stays;
Comparing providers or hospitals by raw averages is misleading: one that treats sicker patients will look worse even if its care is better. Compare like with like by grouping within diagnosis or risk groups, show volumes next to rates, and flag small numbers that make rates unstable.
SELECT provider_id, primary_dx_group,
COUNT(*) AS cases,
ROUND(AVG(total_paid), 0) AS avg_cost,
CASE WHEN COUNT(*) < 20 THEN 'low volume' ELSE 'ok' END AS reliability
FROM claims_summary
GROUP BY provider_id, primary_dx_group
ORDER BY primary_dx_group, avg_cost DESC;
Claims tables show what was billed, allowed and paid, often with adjustments and reversals as extra rows. Medication adherence is commonly measured as the share of days in a period a patient had medication available, built from prescription fill dates and days' supply.
SELECT patient_id,
SUM(days_supply) AS days_covered,
ROUND(100.0 * LEAST(SUM(days_supply), 180) / 180, 1) AS pct_days_covered
FROM pharmacy_fills
WHERE drug_class = 'statin'
AND fill_date BETWEEN '2026-01-01' AND '2026-06-29'
GROUP BY patient_id;
Health data is among the most sensitive data there is, and regulations such as HIPAA in the US and India's DPDP Act govern how it is handled. Analysts follow the minimum necessary principle: select only the columns you need, prefer de-identified or aggregated data, never export identifiers you don't need, and suppress small counts that could identify individuals.
SELECT diagnosis_group, age_band,
CASE WHEN COUNT(*) < 11 THEN NULL ELSE COUNT(*) END AS patients -- suppress small cells
FROM deidentified_encounters
GROUP BY diagnosis_group, age_band;
Apply every module to a realistic healthcare dataset.
Healthcare analyst interviews mix standard SQL with domain scenarios: calculate a readmission rate, build a cohort from diagnosis codes, explain how you would protect patient data.
25 questions covering everything above. Score 80% or higher to earn your Healthcare Data Analyst badge on your dashboard.
25 questions · pass at 80%+ to earn your Healthcare Data Analyst badge on your dashboard. One-time payment, lifetime access.