This repository has been archived by the owner on Aug 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 91
/
ventilation.sql
206 lines (204 loc) · 6.07 KB
/
ventilation.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
-- Calculate duration of mechanical ventilation.
-- Some useful cases for debugging:
-- stay_id = 30019660 has a tracheostomy placed in the ICU
-- stay_id = 30000117 has explicit documentation of extubation
-- classify vent settings into modes
WITH tm AS
(
SELECT stay_id, charttime
FROM `physionet-data.mimic_derived.ventilator_setting`
UNION DISTINCT
SELECT stay_id, charttime
FROM `physionet-data.mimic_derived.oxygen_delivery`
)
, vs AS
(
SELECT tm.stay_id, tm.charttime
-- source data columns, here for debug
, o2_delivery_device_1
, COALESCE(ventilator_mode, ventilator_mode_hamilton) AS vent_mode
-- case statement determining the type of intervention
-- done in order of priority: trach > mech vent > NIV > high flow > o2
, CASE
-- tracheostomy
WHEN o2_delivery_device_1 IN
(
'Tracheostomy tube'
-- 'Trach mask ' -- 16435 observations
)
THEN 'Trach'
-- mechanical ventilation
WHEN o2_delivery_device_1 IN
(
'Endotracheal tube'
)
OR ventilator_mode IN
(
'(S) CMV',
'APRV',
'APRV/Biphasic+ApnPress',
'APRV/Biphasic+ApnVol',
'APV (cmv)',
'Ambient',
'Apnea Ventilation',
'CMV',
'CMV/ASSIST',
'CMV/ASSIST/AutoFlow',
'CMV/AutoFlow',
'CPAP/PPS',
'CPAP/PSV+Apn TCPL',
'CPAP/PSV+ApnPres',
'CPAP/PSV+ApnVol',
'MMV',
'MMV/AutoFlow',
'MMV/PSV',
'MMV/PSV/AutoFlow',
'P-CMV',
'PCV+',
'PCV+/PSV',
'PCV+Assist',
'PRES/AC',
'PRVC/AC',
'PRVC/SIMV',
'PSV/SBT',
'SIMV',
'SIMV/AutoFlow',
'SIMV/PRES',
'SIMV/PSV',
'SIMV/PSV/AutoFlow',
'SIMV/VOL',
'SYNCHRON MASTER',
'SYNCHRON SLAVE',
'VOL/AC'
)
OR ventilator_mode_hamilton IN
(
'APRV',
'APV (cmv)',
'Ambient',
'(S) CMV',
'P-CMV',
'SIMV',
'APV (simv)',
'P-SIMV',
'VS',
'ASV'
)
THEN 'InvasiveVent'
-- NIV
WHEN o2_delivery_device_1 IN
(
'Bipap mask ', -- 8997 observations
'CPAP mask ' -- 5568 observations
)
OR ventilator_mode_hamilton IN
(
'DuoPaP',
'NIV',
'NIV-ST'
)
THEN 'NonInvasiveVent'
-- high flow
when o2_delivery_device_1 IN
(
'High flow neb', -- 10785 observations
'High flow nasal cannula' -- 925 observations
)
THEN 'HighFlow'
-- normal oxygen delivery
WHEN o2_delivery_device_1 in
(
'Nasal cannula', -- 153714 observations
'Face tent', -- 24601 observations
'Aerosol-cool', -- 24560 observations
'Non-rebreather', -- 5182 observations
'Venti mask ', -- 1947 observations
'Medium conc mask ', -- 1888 observations
'T-piece', -- 1135 observations
'Ultrasonic neb', -- 9 observations
'Vapomist', -- 3 observations
'Oxymizer' -- 1301 observations
)
THEN 'Oxygen'
-- Not categorized:
-- 'Other', 'None'
ELSE NULL END AS ventilation_status
FROM tm
LEFT JOIN `physionet-data.mimic_derived.ventilator_setting` vs
ON tm.stay_id = vs.stay_id
AND tm.charttime = vs.charttime
LEFT JOIN `physionet-data.mimic_derived.oxygen_delivery` od
ON tm.stay_id = od.stay_id
AND tm.charttime = od.charttime
)
, vd0 AS
(
SELECT
stay_id, charttime
-- source data columns, here for debug
, o2_delivery_device_1
, vent_mode
-- carry over the previous charttime which had the same state
, LAG(charttime, 1) OVER (PARTITION BY stay_id, ventilation_status ORDER BY charttime) AS charttime_lag
-- bring back the next charttime, regardless of the state
-- this will be used as the end time for state transitions
, LEAD(charttime, 1) OVER w AS charttime_lead
, ventilation_status
, LAG(ventilation_status, 1) OVER w AS ventilation_status_lag
FROM vs
WHERE ventilation_status IS NOT NULL
WINDOW w AS (PARTITION BY stay_id ORDER BY charttime)
)
, vd1 as
(
SELECT
stay_id
-- source data columns, here for debug
, o2_delivery_device_1
, vent_mode
, charttime_lag
, charttime
, charttime_lead
, ventilation_status
-- calculate the time since the last event
, DATETIME_DIFF(charttime, charttime_lag, MINUTE)/60 as ventduration
-- now we determine if the current ventilation status is "new", or continuing the previous
, CASE
-- a 14 hour gap always initiates a new event
WHEN DATETIME_DIFF(charttime, charttime_lag, HOUR) >= 14 THEN 1
WHEN ventilation_status_lag IS NULL THEN 1
-- not a new event if identical to the last row
WHEN ventilation_status_lag != ventilation_status THEN 1
ELSE 0
END AS new_status
FROM vd0
)
, vd2 as
(
SELECT vd1.*
-- create a cumulative sum of the instances of new ventilation
-- this results in a monotonic integer assigned to each instance of ventilation
, SUM(new_status) OVER (PARTITION BY stay_id ORDER BY charttime) AS vent_num
FROM vd1
)
-- create the durations for each ventilation instance
SELECT stay_id
, MIN(charttime) AS starttime
-- for the end time of the ventilation event, the time of the *next* setting
-- i.e. if we go NIV -> O2, the end time of NIV is the first row with a documented O2 device
-- ... unless it's been over 14 hours, in which case it's the last row with a documented NIV.
, MAX(
CASE
WHEN charttime_lead IS NULL
OR DATETIME_DIFF(charttime_lead, charttime, HOUR) >= 14
THEN charttime
ELSE charttime_lead
END
) AS endtime
-- all rows with the same vent_num will have the same ventilation_status
-- for efficiency, we use an aggregate here, but we could equally well group by this column
, MAX(ventilation_status) AS ventilation_status
FROM vd2
GROUP BY stay_id, vent_num
HAVING min(charttime) != max(charttime)
;