Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change logic for KDIGO staging #584

Merged
merged 11 commits into from
Aug 16, 2019
104 changes: 19 additions & 85 deletions concepts/organfailure/kdigo-creatinine.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,91 +13,25 @@ select
on ie.subject_id = le.subject_id
and le.ITEMID = 50912
and le.VALUENUM is not null
and le.CHARTTIME between (ie.intime - interval '6' hour) and (ie.intime + interval '7' day)
and le.CHARTTIME between (ie.intime - interval '7' day) and (ie.intime + interval '7' day)
)
-- ***** --
-- Get the highest and lowest creatinine for the first 48 hours of ICU admission
-- also get the first creatinine
-- ***** --
, cr_48hr as
(
select
cr.icustay_id
, cr.creat
-- add in the lowest value in the previous 48 hours/7 days
SELECT
cr.icustay_id
, cr.charttime
-- Create an index that goes from 1, 2, ..., N
-- The index represents how early in the patient's stay a creatinine value was measured
-- Consequently, when we later select index == 1, we only select the first (admission) creatinine
-- In addition, we only select the first stay for the given subject_id
, ROW_NUMBER ()
OVER (PARTITION BY cr.icustay_id
ORDER BY cr.charttime
) as rn_first

-- Similarly, we can get the highest and the lowest creatinine by ordering by VALUENUM
, ROW_NUMBER ()
OVER (PARTITION BY cr.icustay_id
ORDER BY cr.creat DESC
) as rn_highest
, ROW_NUMBER ()
OVER (PARTITION BY cr.icustay_id
ORDER BY cr.creat
) as rn_lowest
from cr
-- limit to the first 48 hours (source table has data up to 7 days)
where cr.charttime <= cr.intime + interval '48' hour
)
-- ***** --
-- Get the highest and lowest creatinine for the first 7 days of ICU admission
-- ***** --
, cr_7day as
(
select
cr.icustay_id
, cr.creat
, cr.charttime
-- We can get the highest and the lowest creatinine by ordering by VALUENUM
, ROW_NUMBER ()
OVER (PARTITION BY cr.icustay_id
ORDER BY cr.creat DESC
) as rn_highest
, ROW_NUMBER ()
OVER (PARTITION BY cr.icustay_id
ORDER BY cr.creat
) as rn_lowest
from cr
)
-- ***** --
-- Final query
-- ***** --
select
ie.subject_id, ie.hadm_id, ie.icustay_id
, cr_48hr_admit.creat as AdmCreat
, cr_48hr_admit.charttime as AdmCreatTime
, cr_48hr_low.creat as LowCreat48hr
, cr_48hr_low.charttime as LowCreat48hrTime
, cr_48hr_high.creat as HighCreat48hr
, cr_48hr_high.charttime as HighCreat48hrTime

, cr_7day_low.creat as LowCreat7day
, cr_7day_low.charttime as LowCreat7dayTime
, cr_7day_high.creat as HighCreat7day
, cr_7day_high.charttime as HighCreat7dayTime

from icustays ie
left join cr_48hr cr_48hr_admit
on ie.icustay_id = cr_48hr_admit.icustay_id
and cr_48hr_admit.rn_first = 1
left join cr_48hr cr_48hr_high
on ie.icustay_id = cr_48hr_high.icustay_id
and cr_48hr_high.rn_highest = 1
left join cr_48hr cr_48hr_low
on ie.icustay_id = cr_48hr_low.icustay_id
and cr_48hr_low.rn_lowest = 1
left join cr_7day cr_7day_high
on ie.icustay_id = cr_7day_high.icustay_id
and cr_7day_high.rn_highest = 1
left join cr_7day cr_7day_low
on ie.icustay_id = cr_7day_low.icustay_id
and cr_7day_low.rn_lowest = 1
order by ie.icustay_id;
, MIN(cr48.creat) AS creat_low_past_48hr
, MIN(cr7.creat) AS creat_low_past_7day
FROM cr
-- add in all creatinine values in the last 48 hours
LEFT JOIN cr cr48
ON cr.icustay_id = cr48.icustay_id
AND cr48.charttime < cr.charttime
AND cr48.charttime >= (cr.charttime - INTERVAL '48' HOUR)
-- add in all creatinine values in the last 7 days hours
LEFT JOIN cr cr7
ON cr.icustay_id = cr7.icustay_id
AND cr7.charttime < cr.charttime
AND cr7.charttime >= (cr.charttime - INTERVAL '7' DAY)
GROUP BY cr.icustay_id, cr.charttime, cr.creat
ORDER BY cr.icustay_id, cr.charttime, cr.creat;
177 changes: 55 additions & 122 deletions concepts/organfailure/kdigo-stages-48hr.sql
Original file line number Diff line number Diff line change
@@ -1,133 +1,66 @@
-- This query checks if the patient had AKI according to KDIGO on admission
-- AKI can be defined either using data from the first 2 days, or first 7 days

-- For urine output: the highest UO in hours 0-48 is used
-- For creatinine: the creatinine value from days 0-2 or 0-7 is used.
-- Baseline creatinine is defined as first measurement in hours [-6, 24] from ICU admit
-- This query checks if the patient had AKI during the first 48 hours of their ICU
-- stay according to the KDIGO guideline.
-- https://kdigo.org/wp-content/uploads/2016/10/KDIGO-2012-AKI-Guideline-English.pdf

DROP MATERIALIZED VIEW IF EXISTS kdigo_stages_48hr;
CREATE MATERIALIZED VIEW kdigo_stages_48hr AS
with uo_6hr as
(
select
ie.icustay_id
-- , uo.charttime
-- , uo.urineoutput_6hr
, min(uo.urineoutput_6hr / uo.weight / 6.0)::numeric as uo6
from icustays ie
inner join kdigo_uo uo
on ie.icustay_id = uo.icustay_id
-- require the patient to be in the ICU for at least 6 hours
-- allows us to have at least 6 hours of documentation
and uo.charttime >= ie.intime + interval '6' hour
and uo.charttime <= ie.intime + interval '48' hour
group by ie.icustay_id
)
, uo_12hr as
-- get the worst staging of creatinine in the first 48 hours
WITH cr_aki AS
(
select
ie.icustay_id
-- , uo.charttime
-- , uo.weight
-- , uo.urineoutput_12hr
, min(uo.urineoutput_12hr / uo.weight / 12.0)::numeric as uo12
from icustays ie
inner join kdigo_uo uo
on ie.icustay_id = uo.icustay_id
-- require the patient to be in the ICU for 12 hours
-- allows us to have at least 12 hours of documentation
and uo.charttime >= ie.intime + interval '12' hour
and uo.charttime <= ie.intime + interval '48' hour
group by ie.icustay_id
SELECT
k.icustay_id
, k.charttime
, k.creat
, k.aki_stage_creat
, ROW_NUMBER() OVER (PARTITION BY k.icustay_id ORDER BY k.aki_stage_creat DESC, k.creat DESC) AS rn
FROM icustays ie
INNER JOIN kdigo_stages k
ON ie.icustay_id = k.icustay_id
WHERE k.charttime > (ie.intime - interval '6' hour)
AND k.charttime <= (ie.intime + interval '48' hour)
AND k.aki_stage_creat IS NOT NULL
)
, uo_24hr as
-- get the worst staging of urine output in the first 48 hours
, uo_aki AS
(
select
ie.icustay_id
-- , uo.charttime
-- , uo.weight
-- , uo.urineoutput_24hr
, min(uo.urineoutput_24hr / uo.weight / 24.0)::numeric as uo24
from icustays ie
inner join kdigo_uo uo
on ie.icustay_id = uo.icustay_id
-- require the patient to be in the ICU for 24 hours
-- allows us to have at least 24 hours of documentation
and uo.charttime >= ie.intime + interval '24' hour
and uo.charttime <= ie.intime + interval '48' hour
group by ie.icustay_id
)
-- stages for UO / creat
, kdigo_stg as
(

select ie.icustay_id
, ie.intime, ie.outtime
, case
when HighCreat48hr >= (LowCreat48hr*3.0) then 3
when HighCreat48hr >= 4 -- note the criteria specify an INCREASE to >=4
and LowCreat48hr <= (3.7) then 3 -- therefore we check that adm <= 3.7
-- TODO: initiation of RRT
when HighCreat48hr >= (LowCreat48hr*2.0) then 2
when HighCreat48hr >= (LowCreat48hr+0.3) then 1
when HighCreat48hr >= (LowCreat48hr*1.5) then 1
when HighCreat48hr is null then null
when LowCreat48hr is null then null
else 0 end as AKI_stage_48hr_creat

-- AKI stages according to urine output
, case
when UO24 < 0.3 then 3
when UO12 = 0 then 3
when UO12 < 0.5 then 2
when UO6 < 0.5 then 1
when UO6 is null then null
else 0 end as AKI_stage_48hr_uo

-- Creatinine information
, HighCreat48hr, HighCreat48hrTime
, LowCreat48hr, LowCreat48hrTime

-- Urine output information: the values and the time of their measurement
, round(UO6,4) as UO6_48hr
, round(UO12,4) as UO12_48hr
, round(UO24,4) as UO24_48hr
from icustays ie
left join uo_6hr on ie.icustay_id = uo_6hr.icustay_id
left join uo_12hr on ie.icustay_id = uo_12hr.icustay_id
left join uo_24hr on ie.icustay_id = uo_24hr.icustay_id
left join KDIGO_CREAT cr on ie.icustay_id = cr.icustay_id
SELECT
k.icustay_id
, k.charttime
, k.uo_rt_6hr, k.uo_rt_12hr, k.uo_rt_24hr
, k.aki_stage_uo
, ROW_NUMBER() OVER
(
PARTITION BY k.icustay_id
ORDER BY k.aki_stage_uo DESC, k.uo_rt_24hr DESC, k.uo_rt_12hr DESC, k.uo_rt_6hr DESC
) AS rn
FROM icustays ie
INNER JOIN kdigo_stages k
ON ie.icustay_id = k.icustay_id
WHERE k.charttime > (ie.intime - interval '6' hour)
AND k.charttime <= (ie.intime + interval '48' hour)
AND k.aki_stage_uo IS NOT NULL
)
-- final table is aki_stage, include worst cr/uo for convenience
select
kd.icustay_id
ie.icustay_id
, cr.charttime as charttime_creat
, cr.creat
, cr.aki_stage_creat
, uo.charttime as charttime_uo
, uo.uo_rt_6hr
, uo.uo_rt_12hr
, uo.uo_rt_24hr
, uo.aki_stage_uo

-- Classify AKI using both creatinine/urine output criteria
, case
when coalesce(AKI_stage_48hr_creat,AKI_stage_48hr_uo) > 0 then 1
else coalesce(AKI_stage_48hr_creat,AKI_stage_48hr_uo)
end as AKI_48hr

, case
when AKI_stage_48hr_creat >= AKI_stage_48hr_uo then AKI_stage_48hr_creat
when AKI_stage_48hr_uo > AKI_stage_48hr_creat then AKI_stage_48hr_uo
else coalesce(AKI_stage_48hr_creat,AKI_stage_48hr_uo)
end as AKI_stage_48hr

-- components
, AKI_stage_48hr_creat
, AKI_stage_48hr_uo

-- Creatinine information - convert absolute times to hours since admission
, LowCreat48hr
, HighCreat48hr
, ROUND(extract(epoch from (LowCreat48hrTime-intime))::numeric / 60.0 / 60.0 / 24.0, 4) as LowCreat48hrTimeElapsed
, ROUND(extract(epoch from (HighCreat48hrTime-intime))::numeric / 60.0 / 60.0 / 24.0, 4) as HighCreat48hrTimeElapsed
, LowCreat48hrTime
, HighCreat48hrTime
, GREATEST(cr.aki_stage_creat,uo.aki_stage_uo) AS aki_stage_48hr
, CASE WHEN GREATEST(cr.aki_stage_creat, uo.aki_stage_uo) > 0 THEN 1 ELSE 0 END AS aki_48hr

-- Urine output information: the values and the time of their measurement
, UO6_48hr
, UO12_48hr
, UO24_48hr
from kdigo_stg kd
order by kd.icustay_id;
FROM icustays ie
LEFT JOIN cr_aki cr
ON ie.icustay_id = cr.icustay_id
AND cr.rn = 1
LEFT JOIN uo_aki uo
ON ie.icustay_id = uo.icustay_id
AND uo.rn = 1
order by ie.icustay_id;
Loading