Files
mimic-iv-concepts-port/sql/sepsis/suspicion_of_infection.sql

154 lines
5.6 KiB
MySQL
Raw Normal View History

2026-05-05 10:22:17 +02:00
-- ------------------------------------------------------------------
-- Title: Suspicion of Infection
--
-- Adapted from the MIMIC-IV upstream
-- concepts/sepsis/suspicion_of_infection.sql
-- and ported to MIMIC-III v1.3 vanilla PostgreSQL.
--
-- Definition (from the original Sepsis-3 paper, Seymour 2016):
-- a patient is "suspected of infection" if a culture and an
-- antibiotic are ordered close in time:
-- - culture <= 72 h before antibiotic, OR
-- - culture <= 24 h after antibiotic.
-- The antibiotic time is taken as the suspected-infection time when
-- a culture comes second; the culture time when it comes first.
--
-- PORT NOTES:
-- 1. ID column is `icustay_id`, not `stay_id`.
-- 2. MIMIC-III has no `micro_specimen_id`; specimens are identified
-- by the tuple (subject_id, hadm_id, chartdate, charttime,
-- spec_itemid, spec_type_desc) and we deduplicate organism
-- rows by aggregating with that tuple.
-- 3. MIMIC-III `prescriptions.startdate` is DATE-precision only.
-- Consequently `antibiotic_time` always lands on midnight; the
-- MIMIC-IV branches that compare to `me.charttime` still work
-- (DATE auto-casts to TIMESTAMP at 00:00) but give day-level
-- onset precision.
-- ------------------------------------------------------------------
DROP TABLE IF EXISTS suspicion_of_infection;
CREATE TABLE suspicion_of_infection AS
WITH ab_tbl AS
(
SELECT abx.subject_id
, abx.hadm_id
, abx.icustay_id
, abx.antibiotic
, CAST(abx.starttime AS TIMESTAMP) AS antibiotic_time
, CAST(abx.starttime AS DATE) AS antibiotic_date
, CAST(abx.stoptime AS TIMESTAMP) AS antibiotic_stoptime
, ROW_NUMBER() OVER (
PARTITION BY abx.subject_id
ORDER BY abx.starttime, abx.stoptime, abx.antibiotic
) AS ab_id
FROM antibiotic abx
)
, me AS
(
SELECT subject_id, hadm_id
, spec_itemid
, spec_type_desc
, MAX(CAST(chartdate AS DATE)) AS chartdate
, MAX(charttime) AS charttime
, MAX(CASE WHEN org_name IS NOT NULL AND org_name != ''
THEN 1 ELSE 0 END) AS positiveculture
FROM microbiologyevents
GROUP BY subject_id, hadm_id, chartdate, charttime,
spec_itemid, spec_type_desc
)
, me_then_ab AS
(
SELECT ab_tbl.subject_id
, ab_tbl.hadm_id
, ab_tbl.icustay_id
, ab_tbl.ab_id
, COALESCE(me72.charttime,
CAST(me72.chartdate AS TIMESTAMP)) AS last72_charttime
, me72.positiveculture AS last72_positiveculture
, me72.spec_type_desc AS last72_specimen
, ROW_NUMBER() OVER (
PARTITION BY ab_tbl.subject_id, ab_tbl.ab_id
ORDER BY me72.chartdate, me72.charttime NULLS LAST
) AS micro_seq
FROM ab_tbl
LEFT JOIN me me72
ON ab_tbl.subject_id = me72.subject_id
AND (
(
me72.charttime IS NOT NULL
AND ab_tbl.antibiotic_time > me72.charttime
AND ab_tbl.antibiotic_time <= DATETIME_ADD(me72.charttime, INTERVAL '72' HOUR)
)
OR (
me72.charttime IS NULL
AND ab_tbl.antibiotic_date >= me72.chartdate
AND ab_tbl.antibiotic_date <= me72.chartdate + INTERVAL '3 day'
)
)
)
, ab_then_me AS
(
SELECT ab_tbl.subject_id
, ab_tbl.hadm_id
, ab_tbl.icustay_id
, ab_tbl.ab_id
, COALESCE(me24.charttime,
CAST(me24.chartdate AS TIMESTAMP)) AS next24_charttime
, me24.positiveculture AS next24_positiveculture
, me24.spec_type_desc AS next24_specimen
, ROW_NUMBER() OVER (
PARTITION BY ab_tbl.subject_id, ab_tbl.ab_id
ORDER BY me24.chartdate, me24.charttime NULLS LAST
) AS micro_seq
FROM ab_tbl
LEFT JOIN me me24
ON ab_tbl.subject_id = me24.subject_id
AND (
(
me24.charttime IS NOT NULL
AND ab_tbl.antibiotic_time >= DATETIME_SUB(me24.charttime, INTERVAL '24' HOUR)
AND ab_tbl.antibiotic_time < me24.charttime
)
OR (
me24.charttime IS NULL
AND ab_tbl.antibiotic_date >= me24.chartdate - INTERVAL '1 day'
AND ab_tbl.antibiotic_date <= me24.chartdate
)
)
)
SELECT ab_tbl.subject_id
, ab_tbl.icustay_id
, ab_tbl.hadm_id
, ab_tbl.ab_id
, ab_tbl.antibiotic
, ab_tbl.antibiotic_time
, CASE
WHEN me2ab.last72_specimen IS NULL AND ab2me.next24_specimen IS NULL
THEN 0 ELSE 1
END AS suspected_infection
, CASE
WHEN me2ab.last72_specimen IS NULL AND ab2me.next24_specimen IS NULL
THEN NULL
ELSE COALESCE(me2ab.last72_charttime, ab_tbl.antibiotic_time)
END AS suspected_infection_time
, COALESCE(me2ab.last72_charttime, ab2me.next24_charttime) AS culture_time
, COALESCE(me2ab.last72_specimen, ab2me.next24_specimen) AS specimen
, COALESCE(me2ab.last72_positiveculture,
ab2me.next24_positiveculture) AS positive_culture
FROM ab_tbl
LEFT JOIN ab_then_me ab2me
ON ab_tbl.subject_id = ab2me.subject_id
AND ab_tbl.ab_id = ab2me.ab_id
AND ab2me.micro_seq = 1
LEFT JOIN me_then_ab me2ab
ON ab_tbl.subject_id = me2ab.subject_id
AND ab_tbl.ab_id = me2ab.ab_id
AND me2ab.micro_seq = 1;
CREATE INDEX IF NOT EXISTS suspicion_of_infection_idx
ON suspicion_of_infection (icustay_id, suspected_infection_time);