Medication Analysis — Prescribing Patterns and Polypharmacy

Medication Analysis — Prescribing Patterns and Polypharmacy

Medication data reveals prescribing habits, treatment duration, and polypharmacy risk. This lesson covers the most prescribed drugs, duration analysis, concurrent medication counts, and drug-ward correlations.


1. Most Prescribed Drugs

SELECT
    drug_name,
    COUNT(*)                          AS prescriptions,
    ROUND(AVG(dosage_mg), 1)          AS avg_dosage_mg,
    COUNT(DISTINCT admission_id)      AS distinct_admissions,
    (ARRAY_AGG(frequency ORDER BY frequency))[1] AS most_common_frequency
FROM hc_medications
GROUP BY drug_name
ORDER BY prescriptions DESC;

What This Returns

drug_name         | prescriptions | avg_dosage_mg | distinct_admissions
------------------+---------------+---------------+--------------------
Metoprolol        |            80 |          25.0 |                  80
Lisinopril        |            80 |          10.0 |                  80
Atorvastatin      |            80 |          40.0 |                  80
...

2. Average Medication Duration by Drug

Duration = end_date - start_date. Admissions with open-ended medications (end_date IS NULL) get a duration up to today:

SELECT
    drug_name,
    route,
    COUNT(*)                                               AS prescriptions,
    ROUND(AVG(
        COALESCE(end_date, CURRENT_DATE) - start_date
    ), 1)                                                  AS avg_duration_days,
    ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (
        ORDER BY COALESCE(end_date, CURRENT_DATE) - start_date
    )::NUMERIC, 1)                                         AS median_duration_days,
    COUNT(*) FILTER (WHERE end_date IS NULL)               AS open_prescriptions
FROM hc_medications
GROUP BY drug_name, route
ORDER BY avg_duration_days DESC;

3. Polypharmacy — Admissions with 5+ Concurrent Medications

Polypharmacy (5+ drugs simultaneously) is a major adverse event risk. Detect it by finding admissions where multiple medications overlap on the same date:

WITH daily_counts AS (
    SELECT
        m.admission_id,
        d.day,
        COUNT(m.id) AS concurrent_meds
    FROM hc_medications m
    CROSS JOIN LATERAL (
        SELECT generate_series(
            m.start_date,
            COALESCE(m.end_date, m.start_date + 30),
            INTERVAL '1 day'
        )::DATE AS day
    ) d
    GROUP BY m.admission_id, d.day
)
SELECT
    dc.admission_id,
    p.name          AS patient_name,
    p.mrn,
    MAX(dc.concurrent_meds) AS peak_concurrent_meds,
    COUNT(DISTINCT dc.day) FILTER (WHERE dc.concurrent_meds >= 5) AS days_polypharmacy
FROM daily_counts dc
JOIN hc_admissions a ON a.id = dc.admission_id
JOIN hc_patients p   ON p.id = a.patient_id
WHERE dc.concurrent_meds >= 5
GROUP BY dc.admission_id, p.name, p.mrn
ORDER BY peak_concurrent_meds DESC, days_polypharmacy DESC;

4. Drug-Ward Correlation

Which wards prescribe which drugs most often? This informs formulary decisions:

SELECT
    w.name            AS ward,
    m.drug_name,
    COUNT(m.id)       AS prescriptions,
    ROUND(100.0 * COUNT(m.id) / SUM(COUNT(m.id)) OVER (PARTITION BY w.name), 1) AS pct_of_ward_prescriptions
FROM hc_medications m
JOIN hc_admissions a ON a.id = m.admission_id
JOIN hc_wards w      ON w.id = a.ward_id
GROUP BY w.name, m.drug_name
ORDER BY w.name, prescriptions DESC;

5. Antibiotic Stewardship — Duration Outliers

Identify unusually long antibiotic courses (proxy for stewardship gaps):

SELECT
    m.admission_id,
    m.drug_name,
    m.start_date,
    m.end_date,
    m.end_date - m.start_date        AS duration_days,
    p.name,
    p.mrn,
    w.name                           AS ward
FROM hc_medications m
JOIN hc_admissions a ON a.id = m.admission_id
JOIN hc_patients p   ON p.id = a.patient_id
JOIN hc_wards w      ON w.id = a.ward_id
WHERE m.drug_name = 'Amoxicillin'
  AND m.end_date IS NOT NULL
  AND (m.end_date - m.start_date) > 14
ORDER BY duration_days DESC;

Key Takeaway

The CROSS JOIN LATERAL generate_series trick expands each medication row into one row per day, enabling concurrent-medication counting at daily granularity. This is more accurate than just counting medications per admission because it respects the actual overlap window. Use the same pattern for overlapping bookings, overlapping contracts, or any "resource contention at a point in time" problem.