diff --git a/mimic-iii/concepts_postgres/pivot/pivoted_bg.sql b/mimic-iii/concepts_postgres/pivot/pivoted_bg.sql new file mode 100644 index 000000000..84e70c2e0 --- /dev/null +++ b/mimic-iii/concepts_postgres/pivot/pivoted_bg.sql @@ -0,0 +1,196 @@ +-- ===================================================================== +-- PostgreSQL version of BigQuery pivoted-bg.sql (MIMIC-III) +-- Purpose: Pivot blood gas / chemistry values from labevents, and assign +-- them to an icustay_id using fuzzy ICU boundaries. +-- +-- Expected schemas (recommended for PR): +-- mimiciii_clinical: raw MIMIC-III tables (icustays, labevents, admissions) +-- mimiciii_derived : derived concepts output schema (where this table lives) +-- +-- Dependencies: +-- - postgres-functions.sql should be loaded (for DATETIME_ADD/SUB/DIFF) +-- NOTE: This script only uses DATETIME_ADD/SUB/DIFF style patterns, +-- but is also valid if you replace them with native +/- intervals. +-- +-- Output table name (suggested): +-- mimiciii_derived.pivoted_bg +-- ===================================================================== + +DROP TABLE IF EXISTS mimiciii_derived.pivoted_bg; + +CREATE TABLE mimiciii_derived.pivoted_bg AS +WITH i AS +( + SELECT + subject_id + , icustay_id + , intime + , outtime + , LAG(outtime) OVER (PARTITION BY subject_id ORDER BY intime) AS outtime_lag + , LEAD(intime) OVER (PARTITION BY subject_id ORDER BY intime) AS intime_lead + FROM mimiciii_clinical.icustays +) +, iid_assign AS +( + SELECT + i.subject_id + , i.icustay_id + , CASE + WHEN i.outtime_lag IS NOT NULL + AND i.outtime_lag > (i.intime - INTERVAL '24' HOUR) + THEN i.intime + - (INTERVAL '1' HOUR + * CAST(ROUND( (EXTRACT(EPOCH FROM (i.intime - i.outtime_lag)) / 3600.0) / 2.0 ) AS BIGINT)) + ELSE i.intime - INTERVAL '12' HOUR + END AS data_start + , CASE + WHEN i.intime_lead IS NOT NULL + AND i.intime_lead < (i.outtime + INTERVAL '24' HOUR) + THEN i.outtime + + (INTERVAL '1' MINUTE + * CAST(ROUND( (EXTRACT(EPOCH FROM (i.intime_lead - i.outtime)) / 60.0) / 2.0 ) AS BIGINT)) + ELSE i.outtime + INTERVAL '12' HOUR + END AS data_end + FROM i +) +, pvt AS +( + SELECT + le.hadm_id + , CASE + WHEN le.itemid = 50800 THEN 'SPECIMEN' + WHEN le.itemid = 50801 THEN 'AADO2' + WHEN le.itemid = 50802 THEN 'BASEEXCESS' + WHEN le.itemid = 50803 THEN 'BICARBONATE' + WHEN le.itemid = 50804 THEN 'TOTALCO2' + WHEN le.itemid = 50805 THEN 'CARBOXYHEMOGLOBIN' + WHEN le.itemid = 50806 THEN 'CHLORIDE' + WHEN le.itemid = 50808 THEN 'CALCIUM' + WHEN le.itemid = 50809 THEN 'GLUCOSE' + WHEN le.itemid = 50810 THEN 'HEMATOCRIT' + WHEN le.itemid = 50811 THEN 'HEMOGLOBIN' + WHEN le.itemid = 50812 THEN 'INTUBATED' + WHEN le.itemid = 50813 THEN 'LACTATE' + WHEN le.itemid = 50814 THEN 'METHEMOGLOBIN' + WHEN le.itemid = 50815 THEN 'O2FLOW' + WHEN le.itemid = 50816 THEN 'FIO2' + WHEN le.itemid = 50817 THEN 'SO2' + WHEN le.itemid = 50818 THEN 'PCO2' + WHEN le.itemid = 50819 THEN 'PEEP' + WHEN le.itemid = 50820 THEN 'PH' + WHEN le.itemid = 50821 THEN 'PO2' + WHEN le.itemid = 50822 THEN 'POTASSIUM' + WHEN le.itemid = 50823 THEN 'REQUIREDO2' + WHEN le.itemid = 50824 THEN 'SODIUM' + WHEN le.itemid = 50825 THEN 'TEMPERATURE' + WHEN le.itemid = 50826 THEN 'TIDALVOLUME' + WHEN le.itemid = 50827 THEN 'VENTILATIONRATE' + WHEN le.itemid = 50828 THEN 'VENTILATOR' + ELSE NULL + END AS label + , le.charttime + , le.value + , CASE + WHEN le.valuenum IS NULL THEN NULL + WHEN le.valuenum <= 0 THEN NULL + WHEN le.itemid = 50810 AND le.valuenum > 100 THEN NULL -- hematocrit + WHEN le.itemid = 50816 AND le.valuenum < 20 THEN NULL -- fio2 lower bound + WHEN le.itemid = 50816 AND le.valuenum > 100 THEN NULL -- fio2 upper bound + WHEN le.itemid = 50817 AND le.valuenum > 100 THEN NULL -- o2 sat + WHEN le.itemid = 50815 AND le.valuenum > 70 THEN NULL -- o2 flow + WHEN le.itemid = 50821 AND le.valuenum > 800 THEN NULL -- po2 + ELSE le.valuenum + END AS valuenum + FROM mimiciii_clinical.labevents le + WHERE le.itemid IN + ( + 50800, 50801, 50802, 50803, 50804, 50805, 50806, 50807, 50808, 50809 + , 50810, 50811, 50812, 50813, 50814, 50815, 50816, 50817, 50818, 50819 + , 50820, 50821, 50822, 50823, 50824, 50825, 50826, 50827, 50828 + , 51545 + ) +) +, grp AS +( + SELECT + pvt.hadm_id + , pvt.charttime + , MAX(CASE WHEN label = 'SPECIMEN' THEN value ELSE NULL END) AS specimen + , AVG(CASE WHEN label = 'AADO2' THEN valuenum ELSE NULL END) AS aado2 + , AVG(CASE WHEN label = 'BASEEXCESS' THEN valuenum ELSE NULL END) AS baseexcess + , AVG(CASE WHEN label = 'BICARBONATE' THEN valuenum ELSE NULL END) AS bicarbonate + , AVG(CASE WHEN label = 'TOTALCO2' THEN valuenum ELSE NULL END) AS totalco2 + , AVG(CASE WHEN label = 'CARBOXYHEMOGLOBIN' THEN valuenum ELSE NULL END) AS carboxyhemoglobin + , AVG(CASE WHEN label = 'CHLORIDE' THEN valuenum ELSE NULL END) AS chloride + , AVG(CASE WHEN label = 'CALCIUM' THEN valuenum ELSE NULL END) AS calcium + , AVG(CASE WHEN label = 'GLUCOSE' THEN valuenum ELSE NULL END) AS glucose + , AVG(CASE WHEN label = 'HEMATOCRIT' THEN valuenum ELSE NULL END) AS hematocrit + , AVG(CASE WHEN label = 'HEMOGLOBIN' THEN valuenum ELSE NULL END) AS hemoglobin + , AVG(CASE WHEN label = 'INTUBATED' THEN valuenum ELSE NULL END) AS intubated + , AVG(CASE WHEN label = 'LACTATE' THEN valuenum ELSE NULL END) AS lactate + , AVG(CASE WHEN label = 'METHEMOGLOBIN' THEN valuenum ELSE NULL END) AS methemoglobin + , AVG(CASE WHEN label = 'O2FLOW' THEN valuenum ELSE NULL END) AS o2flow + , AVG(CASE WHEN label = 'FIO2' THEN valuenum ELSE NULL END) AS fio2 + , AVG(CASE WHEN label = 'SO2' THEN valuenum ELSE NULL END) AS so2 + , AVG(CASE WHEN label = 'PCO2' THEN valuenum ELSE NULL END) AS pco2 + , AVG(CASE WHEN label = 'PEEP' THEN valuenum ELSE NULL END) AS peep + , AVG(CASE WHEN label = 'PH' THEN valuenum ELSE NULL END) AS ph + , AVG(CASE WHEN label = 'PO2' THEN valuenum ELSE NULL END) AS po2 + , AVG(CASE WHEN label = 'POTASSIUM' THEN valuenum ELSE NULL END) AS potassium + , AVG(CASE WHEN label = 'REQUIREDO2' THEN valuenum ELSE NULL END) AS requiredo2 + , AVG(CASE WHEN label = 'SODIUM' THEN valuenum ELSE NULL END) AS sodium + , AVG(CASE WHEN label = 'TEMPERATURE' THEN valuenum ELSE NULL END) AS temperature + , AVG(CASE WHEN label = 'TIDALVOLUME' THEN valuenum ELSE NULL END) AS tidalvolume + , MAX(CASE WHEN label = 'VENTILATIONRATE' THEN valuenum ELSE NULL END) AS ventilationrate + , MAX(CASE WHEN label = 'VENTILATOR' THEN valuenum ELSE NULL END) AS ventilator + , SUM(CASE WHEN label = 'SPECIMEN' THEN 1 ELSE 0 END) AS specimen_ct + FROM pvt + GROUP BY pvt.hadm_id, pvt.charttime + HAVING SUM(CASE WHEN label = 'SPECIMEN' THEN 1 ELSE 0 END) < 2 +) +SELECT + iid.icustay_id + , grp.hadm_id + , grp.charttime + , grp.specimen + , grp.aado2 + , grp.baseexcess + , grp.bicarbonate + , grp.totalco2 + , grp.carboxyhemoglobin + , grp.chloride + , grp.calcium + , grp.glucose + , grp.hematocrit + , grp.hemoglobin + , grp.intubated + , grp.lactate + , grp.methemoglobin + , grp.o2flow + , grp.fio2 + , grp.so2 + , grp.pco2 + , grp.peep + , grp.ph + , grp.po2 + , grp.potassium + , grp.requiredo2 + , grp.sodium + , grp.temperature + , grp.tidalvolume + , grp.ventilationrate + , grp.ventilator +FROM grp +INNER JOIN mimiciii_clinical.admissions adm + ON grp.hadm_id = adm.hadm_id +LEFT JOIN iid_assign iid + ON adm.subject_id = iid.subject_id + AND grp.charttime >= iid.data_start + AND grp.charttime < iid.data_end +ORDER BY grp.hadm_id, grp.charttime; + +-- Suggested indexes (optional, but helps downstream joins a lot): +-- CREATE INDEX IF NOT EXISTS idx_pivoted_bg_icustay_charttime +-- ON mimiciii_derived.pivoted_bg (icustay_id, charttime); +-- CREATE INDEX IF NOT EXISTS idx_pivoted_bg_hadm_charttime +-- ON mimiciii_derived.pivoted_bg (hadm_id, charttime); diff --git a/mimic-iii/concepts_postgres/pivot/pivoted_bg_art.sql b/mimic-iii/concepts_postgres/pivot/pivoted_bg_art.sql new file mode 100644 index 000000000..26eef8ae1 --- /dev/null +++ b/mimic-iii/concepts_postgres/pivot/pivoted_bg_art.sql @@ -0,0 +1,174 @@ +-- ===================================================================== +-- PostgreSQL version of BigQuery pivoted-bg-art.sql (MIMIC-III) +-- Requires: mimiciii_derived.pivoted_bg +-- +-- Output: mimiciii_derived.pivoted_bg_art +-- ===================================================================== + +DROP TABLE IF EXISTS mimiciii_derived.pivoted_bg_art; + +CREATE TABLE mimiciii_derived.pivoted_bg_art AS +WITH stg_spo2 AS +( + SELECT + hadm_id + , charttime + , AVG(valuenum) AS spo2 + FROM mimiciii_clinical.chartevents + WHERE itemid IN (646, 220277) -- SpO2 + AND valuenum > 0 AND valuenum <= 100 + AND charttime IS NOT NULL + GROUP BY hadm_id, charttime +) +, stg_fio2 AS +( + SELECT + hadm_id + , charttime + , MAX( + CASE + WHEN itemid = 223835 THEN + CASE + WHEN valuenum > 0 AND valuenum <= 1 THEN valuenum * 100 + WHEN valuenum > 1 AND valuenum < 21 THEN NULL + WHEN valuenum >= 21 AND valuenum <= 100 THEN valuenum + ELSE NULL + END + WHEN itemid IN (3420, 3422) THEN + valuenum + WHEN itemid = 190 AND valuenum > 0.20 AND valuenum < 1 THEN + valuenum * 100 + ELSE NULL + END + ) AS fio2_chartevents + FROM mimiciii_clinical.chartevents + WHERE itemid IN (3420, 190, 223835, 3422) + AND valuenum > 0 AND valuenum < 100 + AND charttime IS NOT NULL + -- exclude rows marked as error (if column exists in your import) + AND (error IS NULL OR error <> 1) + GROUP BY hadm_id, charttime +) +, stg2 AS +( + SELECT + bg.* + , ROW_NUMBER() OVER + (PARTITION BY bg.hadm_id, bg.charttime + ORDER BY s1.charttime DESC NULLS LAST) AS lastrowspo2 + , s1.spo2 + FROM mimiciii_derived.pivoted_bg bg + LEFT JOIN stg_spo2 s1 + ON bg.hadm_id = s1.hadm_id + AND s1.charttime BETWEEN (bg.charttime - INTERVAL '2' HOUR) AND bg.charttime + WHERE bg.po2 IS NOT NULL +) +, stg3 AS +( + SELECT + bg.* + , ROW_NUMBER() OVER + (PARTITION BY bg.hadm_id, bg.charttime + ORDER BY s2.charttime DESC NULLS LAST) AS lastrowfio2 + , s2.fio2_chartevents + + -- Logistic regression probability (same coefficients as BigQuery) + , 1.0 / (1.0 + EXP(-( + -0.02544 + + 0.04598 * po2 + + COALESCE(-0.15356 * spo2 , -0.15356 * 97.49420 + 0.13429) + + COALESCE( 0.00621 * fio2_chartevents, 0.00621 * 51.49550 - 0.24958) + + COALESCE( 0.10559 * hemoglobin , 0.10559 * 10.32307 + 0.05954) + + COALESCE( 0.13251 * so2 , 0.13251 * 93.66539 - 0.23172) + + COALESCE(-0.01511 * pco2 , -0.01511 * 42.08866 - 0.01630) + + COALESCE( 0.01480 * fio2 , 0.01480 * 63.97836 - 0.31142) + + COALESCE(-0.00200 * aado2 , -0.00200 * 442.21186 - 0.01328) + + COALESCE(-0.03220 * bicarbonate , -0.03220 * 22.96894 - 0.06535) + + COALESCE( 0.05384 * totalco2 , 0.05384 * 24.72632 - 0.01405) + + COALESCE( 0.08202 * lactate , 0.08202 * 3.06436 + 0.06038) + + COALESCE( 0.10956 * ph , 0.10956 * 7.36233 - 0.00617) + + COALESCE( 0.00848 * o2flow , 0.00848 * 7.59362 - 0.35803) + ))) AS specimen_prob + FROM stg2 bg + LEFT JOIN stg_fio2 s2 + ON bg.hadm_id = s2.hadm_id + AND s2.charttime BETWEEN (bg.charttime - INTERVAL '4' HOUR) AND bg.charttime + AND s2.fio2_chartevents > 0 + WHERE bg.lastrowspo2 = 1 +) +SELECT + stg3.hadm_id + , stg3.icustay_id + , stg3.charttime + , stg3.specimen + + , CASE + WHEN stg3.specimen IS NOT NULL THEN stg3.specimen + WHEN stg3.specimen_prob > 0.75 THEN 'ART' + ELSE NULL + END AS specimen_pred + , stg3.specimen_prob + + -- oxygen related parameters + , stg3.so2 + , stg3.spo2 + , stg3.po2 + , stg3.pco2 + , stg3.fio2_chartevents + , stg3.fio2 + , stg3.aado2 + + , CASE + WHEN stg3.po2 IS NOT NULL + AND stg3.pco2 IS NOT NULL + AND COALESCE(stg3.fio2, stg3.fio2_chartevents) IS NOT NULL + THEN (COALESCE(stg3.fio2, stg3.fio2_chartevents) / 100.0) * (760 - 47) - (stg3.pco2 / 0.8) - stg3.po2 + ELSE NULL + END AS aado2_calc + + , CASE + WHEN stg3.po2 IS NOT NULL + AND COALESCE(stg3.fio2, stg3.fio2_chartevents) IS NOT NULL + THEN 100.0 * stg3.po2 / COALESCE(stg3.fio2, stg3.fio2_chartevents) + ELSE NULL + END AS pao2fio2ratio + + -- acid-base parameters + , stg3.ph + , stg3.baseexcess + , stg3.bicarbonate + , stg3.totalco2 + + -- blood count parameters + , stg3.hematocrit + , stg3.hemoglobin + , stg3.carboxyhemoglobin + , stg3.methemoglobin + + -- chemistry + , stg3.chloride + , stg3.calcium + , stg3.temperature + , stg3.potassium + , stg3.sodium + , stg3.lactate + , stg3.glucose + + -- ventilation / misc + , stg3.intubated + , stg3.tidalvolume + , stg3.ventilationrate + , stg3.ventilator + , stg3.peep + , stg3.o2flow + , stg3.requiredo2 +FROM stg3 +WHERE stg3.lastrowfio2 = 1 + AND (stg3.specimen = 'ART' OR stg3.specimen_prob > 0.75) +ORDER BY stg3.hadm_id, stg3.charttime; + +-- Suggested indexes (optional but strongly recommended) +-- CREATE INDEX IF NOT EXISTS idx_pivoted_bg_art_icustay_charttime +-- ON mimiciii_derived.pivoted_bg_art (icustay_id, charttime); +-- CREATE INDEX IF NOT EXISTS idx_pivoted_bg_art_hadm_charttime +-- ON mimiciii_derived.pivoted_bg_art (hadm_id, charttime); diff --git a/mimic-iii/concepts_postgres/pivot/pivoted_gcs.sql b/mimic-iii/concepts_postgres/pivot/pivoted_gcs.sql new file mode 100644 index 000000000..94dcd182c --- /dev/null +++ b/mimic-iii/concepts_postgres/pivot/pivoted_gcs.sql @@ -0,0 +1,122 @@ +-- ===================================================================== +-- PostgreSQL version of BigQuery pivoted-gcs.sql (MIMIC-III) +-- Output table: +-- mimiciii_derived.pivoted_gcs +-- +-- Source: +-- mimiciii_clinical.chartevents +-- ===================================================================== + +DROP TABLE IF EXISTS mimiciii_derived.pivoted_gcs; + +CREATE TABLE mimiciii_derived.pivoted_gcs AS +WITH base AS +( + SELECT + ce.icustay_id + , ce.charttime + , MAX(CASE WHEN ce.itemid IN (454, 223901) THEN ce.valuenum ELSE NULL END) AS gcsmotor + , MAX( + CASE + WHEN ce.itemid = 723 AND ce.value = '1.0 ET/Trach' THEN 0 + WHEN ce.itemid = 223900 AND ce.value = 'No Response-ETT' THEN 0 + WHEN ce.itemid IN (723, 223900) THEN ce.valuenum + ELSE NULL + END + ) AS gcsverbal + , MAX(CASE WHEN ce.itemid IN (184, 220739) THEN ce.valuenum ELSE NULL END) AS gcseyes + , MAX( + CASE + WHEN ce.itemid = 723 AND ce.value = '1.0 ET/Trach' THEN 1 + WHEN ce.itemid = 223900 AND ce.value = 'No Response-ETT' THEN 1 + ELSE 0 + END + ) AS endotrachflag + , ROW_NUMBER() OVER (PARTITION BY ce.icustay_id ORDER BY ce.charttime ASC) AS rn + FROM mimiciii_clinical.chartevents ce + WHERE ce.itemid IN + ( + 184, 454, 723, + 223900, 223901, 220739 + ) + AND (ce.error IS NULL OR ce.error != 1) + AND ce.charttime IS NOT NULL + GROUP BY ce.icustay_id, ce.charttime +) +, gcs_stg0 AS +( + SELECT + b.* + , b2.gcsverbal AS gcsverbalprev + , b2.gcsmotor AS gcsmotorprev + , b2.gcseyes AS gcseyesprev + , CASE + -- replace GCS during sedation with 15 + WHEN b.gcsverbal = 0 THEN 15 + WHEN b.gcsverbal IS NULL AND b2.gcsverbal = 0 THEN 15 + + -- if previously they were intub, but they aren't now, do not use previous GCS values + WHEN b2.gcsverbal = 0 THEN + COALESCE(b.gcsmotor, 6) + + COALESCE(b.gcsverbal, 5) + + COALESCE(b.gcseyes, 4) + + -- otherwise, add up normally, imputing previous if missing now + ELSE + COALESCE(b.gcsmotor, COALESCE(b2.gcsmotor, 6)) + + COALESCE(b.gcsverbal, COALESCE(b2.gcsverbal, 5)) + + COALESCE(b.gcseyes, COALESCE(b2.gcseyes, 4)) + END AS gcs + FROM base b + LEFT JOIN base b2 + ON b.icustay_id = b2.icustay_id + AND b.rn = b2.rn + 1 + AND b2.charttime > (b.charttime - INTERVAL '6' HOUR) +) +, gcs_stg1 AS +( + SELECT + gs.icustay_id + , gs.charttime + , gs.gcs + , COALESCE(gcsmotor, gcsmotorprev) AS gcsmotor + , COALESCE(gcsverbal, gcsverbalprev) AS gcsverbal + , COALESCE(gcseyes, gcseyesprev) AS gcseyes + , (CASE WHEN COALESCE(gcsmotor, gcsmotorprev) IS NULL THEN 0 ELSE 1 END + + CASE WHEN COALESCE(gcsverbal, gcsverbalprev) IS NULL THEN 0 ELSE 1 END + + CASE WHEN COALESCE(gcseyes, gcseyesprev) IS NULL THEN 0 ELSE 1 END) AS components_measured + , endotrachflag + FROM gcs_stg0 gs +) +, gcs_priority AS +( + SELECT + icustay_id + , charttime + , gcs + , gcsmotor + , gcsverbal + , gcseyes + , endotrachflag + , ROW_NUMBER() OVER + ( + PARTITION BY icustay_id, charttime + ORDER BY components_measured DESC, endotrachflag, gcs, charttime DESC + ) AS rn + FROM gcs_stg1 +) +SELECT + icustay_id + , charttime + , gcs + , gcsmotor + , gcsverbal + , gcseyes + , endotrachflag +FROM gcs_priority +WHERE rn = 1 +ORDER BY icustay_id, charttime; + +-- Suggested index (optional) +-- CREATE INDEX IF NOT EXISTS idx_pivoted_gcs_icustay_charttime +-- ON mimiciii_derived.pivoted_gcs (icustay_id, charttime); diff --git a/mimic-iii/concepts_postgres/pivot/pivoted_lab.sql b/mimic-iii/concepts_postgres/pivot/pivoted_lab.sql new file mode 100644 index 000000000..bd851e39c --- /dev/null +++ b/mimic-iii/concepts_postgres/pivot/pivoted_lab.sql @@ -0,0 +1,215 @@ +-- ===================================================================== +-- PostgreSQL version of BigQuery pivoted-lab.sql (MIMIC-III) +-- Purpose: Pivot common labs from LABEVENTS, and assign hadm_id/icustay_id +-- using "fuzzy" admission/ICU windows. +-- +-- Output table: +-- mimiciii_derived.pivoted_lab +-- +-- Source tables: +-- mimiciii_clinical.icustays +-- mimiciii_clinical.admissions +-- mimiciii_clinical.labevents +-- ===================================================================== + +DROP TABLE IF EXISTS mimiciii_derived.pivoted_lab; + +CREATE TABLE mimiciii_derived.pivoted_lab AS +WITH i AS +( + SELECT + subject_id + , icustay_id + , intime + , outtime + , LAG(outtime) OVER (PARTITION BY subject_id ORDER BY intime) AS outtime_lag + , LEAD(intime) OVER (PARTITION BY subject_id ORDER BY intime) AS intime_lead + FROM mimiciii_clinical.icustays +) +, iid_assign AS +( + SELECT + i.subject_id + , i.icustay_id + , CASE + WHEN i.outtime_lag IS NOT NULL + AND i.outtime_lag > (i.intime - INTERVAL '24' HOUR) + THEN i.intime + - (INTERVAL '1' SECOND * CAST(EXTRACT(EPOCH FROM (i.intime - i.outtime_lag))/2 AS BIGINT)) + ELSE i.intime - INTERVAL '12' HOUR + END AS data_start + , CASE + WHEN i.intime_lead IS NOT NULL + AND i.intime_lead < (i.outtime + INTERVAL '24' HOUR) + THEN i.outtime + + (INTERVAL '1' SECOND * CAST(EXTRACT(EPOCH FROM (i.intime_lead - i.outtime))/2 AS BIGINT)) + ELSE i.outtime + INTERVAL '12' HOUR + END AS data_end + FROM i +) +, h AS +( + SELECT + subject_id + , hadm_id + , admittime + , dischtime + , LAG(dischtime) OVER (PARTITION BY subject_id ORDER BY admittime) AS dischtime_lag + , LEAD(admittime) OVER (PARTITION BY subject_id ORDER BY admittime) AS admittime_lead + FROM mimiciii_clinical.admissions +) +, adm AS +( + SELECT + h.subject_id + , h.hadm_id + , CASE + WHEN h.dischtime_lag IS NOT NULL + AND h.dischtime_lag > (h.admittime - INTERVAL '24' HOUR) + THEN h.admittime + - (INTERVAL '1' SECOND * CAST(EXTRACT(EPOCH FROM (h.admittime - h.dischtime_lag))/2 AS BIGINT)) + ELSE h.admittime - INTERVAL '12' HOUR + END AS data_start + , CASE + WHEN h.admittime_lead IS NOT NULL + AND h.admittime_lead < (h.dischtime + INTERVAL '24' HOUR) + THEN h.dischtime + + (INTERVAL '1' SECOND * CAST(EXTRACT(EPOCH FROM (h.admittime_lead - h.dischtime))/2 AS BIGINT)) + ELSE h.dischtime + INTERVAL '12' HOUR + END AS data_end + FROM h +) +, le_avg AS +( + SELECT + pvt.subject_id + , pvt.charttime + , AVG(CASE WHEN label = 'ANION GAP' THEN valuenum ELSE NULL END) AS aniongap + , AVG(CASE WHEN label = 'ALBUMIN' THEN valuenum ELSE NULL END) AS albumin + , AVG(CASE WHEN label = 'BANDS' THEN valuenum ELSE NULL END) AS bands + , AVG(CASE WHEN label = 'BICARBONATE' THEN valuenum ELSE NULL END) AS bicarbonate + , AVG(CASE WHEN label = 'BILIRUBIN' THEN valuenum ELSE NULL END) AS bilirubin + , AVG(CASE WHEN label = 'CREATININE' THEN valuenum ELSE NULL END) AS creatinine + , AVG(CASE WHEN label = 'CHLORIDE' THEN valuenum ELSE NULL END) AS chloride + , AVG(CASE WHEN label = 'GLUCOSE' THEN valuenum ELSE NULL END) AS glucose + , AVG(CASE WHEN label = 'HEMATOCRIT' THEN valuenum ELSE NULL END) AS hematocrit + , AVG(CASE WHEN label = 'HEMOGLOBIN' THEN valuenum ELSE NULL END) AS hemoglobin + , AVG(CASE WHEN label = 'LACTATE' THEN valuenum ELSE NULL END) AS lactate + , AVG(CASE WHEN label = 'PLATELET' THEN valuenum ELSE NULL END) AS platelet + , AVG(CASE WHEN label = 'POTASSIUM' THEN valuenum ELSE NULL END) AS potassium + , AVG(CASE WHEN label = 'PTT' THEN valuenum ELSE NULL END) AS ptt + , AVG(CASE WHEN label = 'INR' THEN valuenum ELSE NULL END) AS inr + , AVG(CASE WHEN label = 'PT' THEN valuenum ELSE NULL END) AS pt + , AVG(CASE WHEN label = 'SODIUM' THEN valuenum ELSE NULL END) AS sodium + , AVG(CASE WHEN label = 'BUN' THEN valuenum ELSE NULL END) AS bun + , AVG(CASE WHEN label = 'WBC' THEN valuenum ELSE NULL END) AS wbc + FROM + ( + SELECT + le.subject_id + , le.hadm_id + , le.charttime + , CASE + WHEN itemid = 50868 THEN 'ANION GAP' + WHEN itemid = 50862 THEN 'ALBUMIN' + WHEN itemid = 51144 THEN 'BANDS' + WHEN itemid = 50882 THEN 'BICARBONATE' + WHEN itemid = 50885 THEN 'BILIRUBIN' + WHEN itemid = 50912 THEN 'CREATININE' + WHEN itemid = 50902 THEN 'CHLORIDE' + WHEN itemid = 50931 THEN 'GLUCOSE' + WHEN itemid = 51221 THEN 'HEMATOCRIT' + WHEN itemid = 51222 THEN 'HEMOGLOBIN' + WHEN itemid = 50813 THEN 'LACTATE' + WHEN itemid = 51265 THEN 'PLATELET' + WHEN itemid = 50971 THEN 'POTASSIUM' + WHEN itemid = 51275 THEN 'PTT' + WHEN itemid = 51237 THEN 'INR' + WHEN itemid = 51274 THEN 'PT' + WHEN itemid = 50983 THEN 'SODIUM' + WHEN itemid = 51006 THEN 'BUN' + WHEN itemid IN (51300, 51301) THEN 'WBC' + ELSE NULL + END AS label + , CASE + WHEN itemid = 50862 AND valuenum > 10 THEN NULL + WHEN itemid = 50868 AND valuenum > 10000 THEN NULL + WHEN itemid = 51144 AND valuenum < 0 THEN NULL + WHEN itemid = 51144 AND valuenum > 100 THEN NULL + WHEN itemid = 50882 AND valuenum > 10000 THEN NULL + WHEN itemid = 50885 AND valuenum > 150 THEN NULL + WHEN itemid = 50806 AND valuenum > 10000 THEN NULL + WHEN itemid = 50902 AND valuenum > 10000 THEN NULL + WHEN itemid = 50912 AND valuenum > 150 THEN NULL + WHEN itemid = 50809 AND valuenum > 10000 THEN NULL + WHEN itemid = 50931 AND valuenum > 10000 THEN NULL + WHEN itemid = 50810 AND valuenum > 100 THEN NULL + WHEN itemid = 51221 AND valuenum > 100 THEN NULL + WHEN itemid = 50811 AND valuenum > 50 THEN NULL + WHEN itemid = 51222 AND valuenum > 50 THEN NULL + WHEN itemid = 50813 AND valuenum > 50 THEN NULL + WHEN itemid = 51265 AND valuenum > 10000 THEN NULL + WHEN itemid = 50822 AND valuenum > 30 THEN NULL + WHEN itemid = 50971 AND valuenum > 30 THEN NULL + WHEN itemid = 51275 AND valuenum > 150 THEN NULL + WHEN itemid = 51237 AND valuenum > 50 THEN NULL + WHEN itemid = 51274 AND valuenum > 150 THEN NULL + WHEN itemid = 50824 AND valuenum > 200 THEN NULL + WHEN itemid = 50983 AND valuenum > 200 THEN NULL + WHEN itemid = 51006 AND valuenum > 300 THEN NULL + WHEN itemid IN (51300, 51301) AND valuenum > 1000 THEN NULL + ELSE valuenum + END AS valuenum + FROM mimiciii_clinical.labevents le + WHERE le.itemid IN + ( + 50868, 50862, 51144, 50882, 50885, 50912, 50902, + 50931, 51221, 51222, 50813, 51265, 50971, 51275, + 51237, 51274, 50983, 51006, 51301, 51300 + ) + AND le.charttime IS NOT NULL + AND le.valuenum IS NOT NULL + AND le.valuenum > 0 + ) pvt + GROUP BY pvt.subject_id, pvt.charttime +) +SELECT + iid.icustay_id + , adm.hadm_id + , le_avg.subject_id + , le_avg.charttime + , le_avg.aniongap + , le_avg.albumin + , le_avg.bands + , le_avg.bicarbonate + , le_avg.bilirubin + , le_avg.creatinine + , le_avg.chloride + , le_avg.glucose + , le_avg.hematocrit + , le_avg.hemoglobin + , le_avg.lactate + , le_avg.platelet + , le_avg.potassium + , le_avg.ptt + , le_avg.inr + , le_avg.pt + , le_avg.sodium + , le_avg.bun + , le_avg.wbc +FROM le_avg +LEFT JOIN adm + ON le_avg.subject_id = adm.subject_id + AND le_avg.charttime >= adm.data_start + AND le_avg.charttime < adm.data_end +LEFT JOIN iid_assign iid + ON le_avg.subject_id = iid.subject_id + AND le_avg.charttime >= iid.data_start + AND le_avg.charttime < iid.data_end +ORDER BY le_avg.subject_id, le_avg.charttime; + +-- Suggested indexes (optional, recommended) +-- CREATE INDEX IF NOT EXISTS idx_pivoted_lab_icustay_charttime +-- ON mimiciii_derived.pivoted_lab (icustay_id, charttime); +-- CREATE INDEX IF NOT EXISTS idx_pivoted_lab_hadm_charttime +-- ON mimiciii_derived.pivoted_lab (hadm_id, charttime); diff --git a/mimic-iii/concepts_postgres/pivot/pivoted_sofa.sql b/mimic-iii/concepts_postgres/pivot/pivoted_sofa.sql new file mode 100644 index 000000000..56e35b882 --- /dev/null +++ b/mimic-iii/concepts_postgres/pivot/pivoted_sofa.sql @@ -0,0 +1,299 @@ +-- ===================================================================== +-- PostgreSQL version of BigQuery pivoted_sofa.sql (MIMIC-III) +-- Output table: +-- mimiciii_derived.pivoted_sofa +-- ===================================================================== + +DROP TABLE IF EXISTS mimiciii_derived.pivoted_sofa; + +CREATE TABLE mimiciii_derived.pivoted_sofa AS +WITH co AS +( + SELECT + ih.icustay_id + , ie.hadm_id + , ih.hr + -- start/endtime can be used to filter to values within this hour + , (ih.endtime - INTERVAL '1' HOUR) AS starttime + , ih.endtime + FROM mimiciii_derived.icustay_hours ih + INNER JOIN mimiciii_clinical.icustays ie + ON ih.icustay_id = ie.icustay_id +) +, bp AS +( + SELECT + ce.icustay_id + , ce.charttime + , MIN(ce.valuenum) AS meanbp_min + FROM mimiciii_clinical.chartevents ce + WHERE (ce.error IS NULL OR ce.error != 1) + AND ce.itemid IN + ( + 456, -- NBP Mean + 52, -- Arterial BP Mean + 6702, -- Arterial BP Mean #2 + 443, -- Manual BP Mean(calc) + 220052, -- Arterial Blood Pressure mean + 220181, -- Non Invasive Blood Pressure mean + 225312 -- ART BP mean + ) + AND ce.valuenum > 0 + AND ce.valuenum < 300 + AND ce.charttime IS NOT NULL + GROUP BY ce.icustay_id, ce.charttime +) +, pafi AS +( + -- join blood gas to ventilation durations to determine if patient was vent + SELECT + ie.icustay_id + , bg.charttime + , CASE WHEN vd.icustay_id IS NULL THEN bg.pao2fio2ratio ELSE NULL END AS pao2fio2ratio_novent + , CASE WHEN vd.icustay_id IS NOT NULL THEN bg.pao2fio2ratio ELSE NULL END AS pao2fio2ratio_vent + FROM mimiciii_clinical.icustays ie + INNER JOIN mimiciii_derived.pivoted_bg_art bg + ON ie.icustay_id = bg.icustay_id + LEFT JOIN mimiciii_derived.ventilation_durations vd + ON ie.icustay_id = vd.icustay_id + AND bg.charttime >= vd.starttime + AND bg.charttime <= vd.endtime + WHERE bg.charttime IS NOT NULL +) +, mini_agg AS +( + SELECT + co.icustay_id + , co.hr + -- vitals + , MIN(bp.meanbp_min) AS meanbp_min + -- gcs + , MIN(gcs.gcs) AS gcs_min + -- labs + , MAX(labs.bilirubin) AS bilirubin_max + , MAX(labs.creatinine) AS creatinine_max + , MIN(labs.platelet) AS platelet_min + -- PaO2/FiO2 with vent interaction + , MIN(CASE WHEN vd.icustay_id IS NULL THEN bg.pao2fio2ratio ELSE NULL END) AS pao2fio2ratio_novent + , MIN(CASE WHEN vd.icustay_id IS NOT NULL THEN bg.pao2fio2ratio ELSE NULL END) AS pao2fio2ratio_vent + FROM co + LEFT JOIN bp + ON co.icustay_id = bp.icustay_id + AND co.starttime < bp.charttime + AND co.endtime >= bp.charttime + LEFT JOIN mimiciii_derived.pivoted_gcs gcs + ON co.icustay_id = gcs.icustay_id + AND co.starttime < gcs.charttime + AND co.endtime >= gcs.charttime + LEFT JOIN mimiciii_derived.pivoted_lab labs + ON co.hadm_id = labs.hadm_id + AND co.starttime < labs.charttime + AND co.endtime >= labs.charttime + -- bring in blood gases that occurred during this hour + LEFT JOIN mimiciii_derived.pivoted_bg_art bg + ON co.icustay_id = bg.icustay_id + AND co.starttime < bg.charttime + AND co.endtime >= bg.charttime + -- at the time of the blood gas, determine if patient was ventilated + LEFT JOIN mimiciii_derived.ventilation_durations vd + ON co.icustay_id = vd.icustay_id + AND bg.charttime >= vd.starttime + AND bg.charttime <= vd.endtime + GROUP BY co.icustay_id, co.hr +) +, uo AS +( + -- sum uo separately to prevent duplicating values + SELECT + co.icustay_id + , co.hr + , SUM(uo.urineoutput) AS urineoutput + FROM co + LEFT JOIN mimiciii_derived.pivoted_uo uo + ON co.icustay_id = uo.icustay_id + AND co.starttime < uo.charttime + AND co.endtime >= uo.charttime + GROUP BY co.icustay_id, co.hr +) +, scorecomp AS +( + SELECT + co.icustay_id + , co.hr + , co.starttime + , co.endtime + , ma.pao2fio2ratio_novent + , ma.pao2fio2ratio_vent + , epi.vaso_rate AS rate_epinephrine + , nor.vaso_rate AS rate_norepinephrine + , dop.vaso_rate AS rate_dopamine + , dob.vaso_rate AS rate_dobutamine + , ma.meanbp_min + , ma.gcs_min + , uo.urineoutput + , ma.bilirubin_max + , ma.creatinine_max + , ma.platelet_min + FROM co + LEFT JOIN mini_agg ma + ON co.icustay_id = ma.icustay_id + AND co.hr = ma.hr + LEFT JOIN uo + ON co.icustay_id = uo.icustay_id + AND co.hr = uo.hr + LEFT JOIN mimiciii_derived.epinephrine_dose epi + ON co.icustay_id = epi.icustay_id + AND co.endtime > epi.starttime + AND co.endtime <= epi.endtime + LEFT JOIN mimiciii_derived.norepinephrine_dose nor + ON co.icustay_id = nor.icustay_id + AND co.endtime > nor.starttime + AND co.endtime <= nor.endtime + LEFT JOIN mimiciii_derived.dopamine_dose dop + ON co.icustay_id = dop.icustay_id + AND co.endtime > dop.starttime + AND co.endtime <= dop.endtime + LEFT JOIN mimiciii_derived.dobutamine_dose dob + ON co.icustay_id = dob.icustay_id + AND co.endtime > dob.starttime + AND co.endtime <= dob.endtime +) +, scorecalc AS +( + SELECT + scorecomp.* + + -- Respiration + , CAST( + CASE + WHEN pao2fio2ratio_vent < 100 THEN 4 + WHEN pao2fio2ratio_vent < 200 THEN 3 + WHEN pao2fio2ratio_novent < 300 THEN 2 + WHEN pao2fio2ratio_novent < 400 THEN 1 + WHEN COALESCE(pao2fio2ratio_vent, pao2fio2ratio_novent) IS NULL THEN NULL + ELSE 0 + END AS SMALLINT + ) AS respiration + + -- Coagulation + , CAST( + CASE + WHEN platelet_min < 20 THEN 4 + WHEN platelet_min < 50 THEN 3 + WHEN platelet_min < 100 THEN 2 + WHEN platelet_min < 150 THEN 1 + WHEN platelet_min IS NULL THEN NULL + ELSE 0 + END AS SMALLINT + ) AS coagulation + + -- Liver (bilirubin mg/dL) + , CAST( + CASE + WHEN bilirubin_max >= 12.0 THEN 4 + WHEN bilirubin_max >= 6.0 THEN 3 + WHEN bilirubin_max >= 2.0 THEN 2 + WHEN bilirubin_max >= 1.2 THEN 1 + WHEN bilirubin_max IS NULL THEN NULL + ELSE 0 + END AS SMALLINT + ) AS liver + + -- Cardiovascular + , CAST( + CASE + WHEN rate_dopamine > 15 OR rate_epinephrine > 0.1 OR rate_norepinephrine > 0.1 THEN 4 + WHEN rate_dopamine > 5 OR rate_epinephrine <= 0.1 OR rate_norepinephrine <= 0.1 THEN 3 + WHEN rate_dopamine > 0 OR rate_dobutamine > 0 THEN 2 + WHEN meanbp_min < 70 THEN 1 + WHEN COALESCE(meanbp_min, rate_dopamine, rate_dobutamine, rate_epinephrine, rate_norepinephrine) IS NULL THEN NULL + ELSE 0 + END AS SMALLINT + ) AS cardiovascular + + -- CNS (GCS) + , CAST( + CASE + WHEN (gcs_min >= 13 AND gcs_min <= 14) THEN 1 + WHEN (gcs_min >= 10 AND gcs_min <= 12) THEN 2 + WHEN (gcs_min >= 6 AND gcs_min <= 9) THEN 3 + WHEN gcs_min < 6 THEN 4 + WHEN gcs_min IS NULL THEN NULL + ELSE 0 + END AS SMALLINT + ) AS cns + + -- Renal (creatinine or urine output) + , CAST( + CASE + WHEN creatinine_max >= 5.0 THEN 4 + WHEN SUM(urineoutput) OVER w < 200 THEN 4 + WHEN (creatinine_max >= 3.5 AND creatinine_max < 5.0) THEN 3 + WHEN SUM(urineoutput) OVER w < 500 THEN 3 + WHEN (creatinine_max >= 2.0 AND creatinine_max < 3.5) THEN 2 + WHEN (creatinine_max >= 1.2 AND creatinine_max < 2.0) THEN 1 + WHEN COALESCE(SUM(urineoutput) OVER w, creatinine_max) IS NULL THEN NULL + ELSE 0 + END AS SMALLINT + ) AS renal + + FROM scorecomp + WINDOW w AS + ( + PARTITION BY icustay_id + ORDER BY hr + ROWS BETWEEN 23 PRECEDING AND CURRENT ROW + ) +) +, score_final AS +( + SELECT + s.* + + -- 24h rolling max for each component (impute 0 if missing) + , CAST(COALESCE( + MAX(respiration) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW) + , 0) AS SMALLINT) AS respiration_24hours + + , CAST(COALESCE( + MAX(coagulation) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW) + , 0) AS SMALLINT) AS coagulation_24hours + + , CAST(COALESCE( + MAX(liver) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW) + , 0) AS SMALLINT) AS liver_24hours + + , CAST(COALESCE( + MAX(cardiovascular) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW) + , 0) AS SMALLINT) AS cardiovascular_24hours + + , CAST(COALESCE( + MAX(cns) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW) + , 0) AS SMALLINT) AS cns_24hours + + , CAST(COALESCE( + MAX(renal) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW) + , 0) AS SMALLINT) AS renal_24hours + + -- total SOFA (sum of 24h rolling max components) + , ( + COALESCE(MAX(respiration) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW), 0) + + COALESCE(MAX(coagulation) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW), 0) + + COALESCE(MAX(liver) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW), 0) + + COALESCE(MAX(cardiovascular) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW), 0) + + COALESCE(MAX(cns) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW), 0) + + COALESCE(MAX(renal) OVER (PARTITION BY icustay_id ORDER BY hr ROWS BETWEEN 24 PRECEDING AND CURRENT ROW), 0) + )::SMALLINT AS sofa_24hours + + FROM scorecalc s +) +SELECT * +FROM score_final +WHERE hr >= 0 +ORDER BY icustay_id, hr; + +-- Suggested indexes (optional) +-- CREATE INDEX IF NOT EXISTS idx_pivoted_sofa_icustay_hr +-- ON mimiciii_derived.pivoted_sofa (icustay_id, hr); +-- CREATE INDEX IF NOT EXISTS idx_pivoted_sofa_icustay_endtime +-- ON mimiciii_derived.pivoted_sofa (icustay_id, endtime); diff --git a/mimic-iii/concepts_postgres/pivot/pivoted_uo.sql b/mimic-iii/concepts_postgres/pivot/pivoted_uo.sql new file mode 100644 index 000000000..ce6642738 --- /dev/null +++ b/mimic-iii/concepts_postgres/pivot/pivoted_uo.sql @@ -0,0 +1,48 @@ +-- ===================================================================== +-- PostgreSQL version of BigQuery pivoted-uo.sql (MIMIC-III) +-- Purpose: Pivot urine output volumes from OUTPUTEVENTS +-- +-- Output table: +-- mimiciii_derived.pivoted_uo +-- +-- Source table: +-- mimiciii_clinical.outputevents +-- ===================================================================== + +DROP TABLE IF EXISTS mimiciii_derived.pivoted_uo; + +CREATE TABLE mimiciii_derived.pivoted_uo AS +SELECT + icustay_id + , charttime + , SUM(urineoutput) AS urineoutput +FROM +( + SELECT + oe.icustay_id + , oe.charttime + , CASE + WHEN oe.itemid = 227488 AND oe.value > 0 THEN -1 * oe.value + ELSE oe.value + END AS urineoutput + FROM mimiciii_clinical.outputevents oe + WHERE (oe.iserror IS NULL OR oe.iserror <> 1) + AND oe.itemid IN + ( + -- CareVue + 40055, 43175, 40069, 40094, 40715, 40473, 40085, 40057, 40056, + 40405, 40428, 40086, 40096, 40651, + + -- MetaVision + 226559, 226560, 226561, 226584, 226563, 226564, 226565, 226567, + 226557, 226558, 227488, 227489 + ) + AND oe.icustay_id IS NOT NULL + AND oe.charttime IS NOT NULL +) t +GROUP BY icustay_id, charttime +ORDER BY icustay_id, charttime; + +-- Suggested index (optional, recommended for downstream joins) +-- CREATE INDEX IF NOT EXISTS idx_pivoted_uo_icustay_charttime +-- ON mimiciii_derived.pivoted_uo (icustay_id, charttime); diff --git a/mimic-iii/concepts_postgres/postgres-make-concepts.sql b/mimic-iii/concepts_postgres/postgres-make-concepts.sql index 50b021029..522acf4ce 100644 --- a/mimic-iii/concepts_postgres/postgres-make-concepts.sql +++ b/mimic-iii/concepts_postgres/postgres-make-concepts.sql @@ -95,4 +95,19 @@ \i severityscores/sirs.sql \i severityscores/sofa.sql --- final tables which were dependent on one or more prior tables + +-- Missing scripts: treatment +\i treatment/abx_prescriptions_list.sql +\i treatment/suspicion_of_infection.sql + +-- New addition: Pivot calculation for SOFA related metrics +\i pivot/pivoted_bg.sql +\i pivot/pivoted_bg_art.sql +\i pivot/pivoted_uo.sql +\i pivot/pivoted_lab.sql +\i pivot/pivoted_gcs.sql + +-- Sepsis 3 script +\i sepsis/sepsis3.sql + + diff --git a/mimic-iii/concepts_postgres/sepsis/sepsis3.sql b/mimic-iii/concepts_postgres/sepsis/sepsis3.sql index 99d6437bf..1b25102ff 100644 --- a/mimic-iii/concepts_postgres/sepsis/sepsis3.sql +++ b/mimic-iii/concepts_postgres/sepsis/sepsis3.sql @@ -1,2 +1,101 @@ --- THIS SCRIPT IS AUTOMATICALLY GENERATED. DO NOT EDIT IT DIRECTLY. -DROP TABLE IF EXISTS sepsis3; CREATE TABLE sepsis3 AS +/* +Creates a table with "onset" time of Sepsis-3 in the ICU (MIMIC-III). + +Definition (aligned to MIMIC-IV sepsis3): +- Sepsis-3 onset in ICU = earliest time where: + (1) SOFA_24hours >= 2 + (2) Suspicion of infection exists (SOI event) + (3) SOFA time is within [-48h, +24h] of suspected_infection_time +Notes: +- Baseline SOFA assumed 0 prior to ICU (same assumption as MIMIC-IV script). +- This defines sepsis-3 onset within ICU only. +*/ + +DROP TABLE IF EXISTS mimiciii_derived.sepsis3; +CREATE TABLE mimiciii_derived.sepsis3 AS +WITH sofa AS ( + SELECT + icustay_id, + starttime, + endtime, + respiration_24hours AS respiration, + coagulation_24hours AS coagulation, + liver_24hours AS liver, + cardiovascular_24hours AS cardiovascular, + cns_24hours AS cns, + renal_24hours AS renal, + sofa_24hours AS sofa_score + FROM mimiciii_derived.pivoted_sofa + WHERE sofa_24hours >= 2 +), +s1 AS ( + SELECT + ie.subject_id, + soi.icustay_id, + + -- suspicion_of_infection columns (MIMIC-III version) + soi.antibiotic_name AS antibiotic, + soi.antibiotic_time, + soi.suspected_infection_time, + soi.specimen, + soi.positiveculture AS positive_culture, + + -- sofa columns + sofa.starttime, + sofa.endtime, + sofa.respiration, + sofa.coagulation, + sofa.liver, + sofa.cardiovascular, + sofa.cns, + sofa.renal, + sofa.sofa_score, + + -- define suspected_infection flag (since MIMIC-III SOI table may not carry it explicitly) + CASE WHEN soi.suspected_infection_time IS NOT NULL THEN 1 ELSE 0 END AS suspected_infection, + + -- Sepsis-3 flag (same logical form as MIMIC-IV) + (sofa.sofa_score >= 2 AND soi.suspected_infection_time IS NOT NULL) AS sepsis3, + + -- pick earliest row per icustay + ROW_NUMBER() OVER ( + PARTITION BY soi.icustay_id + ORDER BY + soi.suspected_infection_time NULLS FIRST, + soi.antibiotic_time NULLS FIRST, + sofa.endtime NULLS FIRST + ) AS rn_sus + + FROM mimiciii_derived.suspicion_of_infection AS soi + INNER JOIN mimiciii_clinical.icustays AS ie + ON soi.icustay_id = ie.icustay_id + INNER JOIN sofa + ON soi.icustay_id = sofa.icustay_id + AND sofa.endtime >= soi.suspected_infection_time - INTERVAL '48 hour' + AND sofa.endtime <= soi.suspected_infection_time + INTERVAL '24 hour' + + -- only include rows with a valid SOI time (otherwise the +/- window is meaningless) + WHERE soi.icustay_id IS NOT NULL + AND soi.suspected_infection_time IS NOT NULL +) +SELECT + subject_id, + icustay_id, + + antibiotic_time, + suspected_infection_time, + + -- endtime is latest time at which the SOFA score is valid (same as MIMIC-IV) + endtime AS sofa_time, + + sofa_score, + respiration, + coagulation, + liver, + cardiovascular, + cns, + renal, + + sepsis3 +FROM s1 +WHERE rn_sus = 1;