SQL 服务器剧集识别

SQL Server episode identification

我正在 SQL 服务器中使用血压数据库,其中包含 patient_idtimestamp(每分钟)和 systolicBloodPressure

我的目标是找到:

  1. 患者低于特定血压阈值的发作次数

    一集由时间图组成,其中患者下降到特定阈值以下,直到患者高于阈值的时间戳。

  2. 每位患者每次发作的平均血压

  3. 每位患者每次发作的持续时间

到目前为止我尝试过的:

我可以通过创建一个新列来识别剧集,如果达到阈值则设置为 1。

    select *
    , CASE
    when sys < threshold THEN '1'
    from BPDATA

但是,我无法 'identify' 患者体内的不同发作;第 1 集第 2 集及其相对时间戳。

有人可以帮我解决这个问题吗?或者有人有更好的不同解决方案吗?

编辑:示例阈值 100 的样本数据

    ID          Timestamp      SysBP      below Threshold
    ----------------------------------------------------
    1             9:38          110       Null
    1             9:39          105       Null
    1             9:40          96        1
    1             9:41          92        1 
    1             9:42          102       Null
    2             12:23         95        1
    2             12:24         98        1
    2             12:25         102       Null
    2             12:26         104       Null
    2             12:27         94        1
    2             12:28         88        1  
    2             12:29         104       Null

感谢您提供示例数据。

这应该有效:

declare @t table (ID int, Timestamp time, SysBP int, belowThreshold bit)
insert @t 
values
(1,              '9:38',          110, null),
(1,              '9:39',          105, null),
(1,              '9:40',           96, 1),
(1,              '9:41',           92, 1),
(1,              '9:42',          102, null),
(2,             '12:23',           95, 1),
(2,             '12:24',           98, 1),
(2,             '12:25',          102, null),
(2,             '12:26',          104, null),
(2,             '12:27',           94, 1),
(2,             '12:28',           88, 1),
(2,             '12:29',          104, null)

declare @treshold int = 100

;with y as (
    select *, case when lag(belowThreshold, 1, 0) over(partition by id order by timestamp) = belowThreshold then 0 else 1 end epg
    from @t
),
z as (
    select *, sum(epg) over(partition by id order by timestamp) episode
    from y
    where sysbp < @treshold
)
select id, episode, count(episode) over(partition by id) number_of_episodes_per_id, avg(sysbp) avg_sysbp, datediff(minute, min(timestamp), max(timestamp))+1 episode_duration
from z
group by id, episode

此答案依赖于 LEAD() 和 LAG() 函数,因此仅适用于 2012 年或之后的版本:

设置:

CREATE TABLE #bloodpressure 
(
    Patient_id int,
    [TimeStamp] SmallDateTime,
    SystolicBloodPressure INT
)

INSERT INTO #bloodpressure
VALUES
(1, '2017-01-01 09:01', 60),
(1, '2017-01-01 09:02', 55),
(1, '2017-01-01 09:03', 60),
(1, '2017-01-01 09:04', 70),
(1, '2017-01-01 09:05', 72),
(1, '2017-01-01 09:06', 75),
(1, '2017-01-01 09:07', 60),
(1, '2017-01-01 09:08', 50),
(1, '2017-01-01 09:09', 52),
(1, '2017-01-01 09:10', 53),
(1, '2017-01-01 09:11', 65),
(1, '2017-01-01 09:12', 71),
(1, '2017-01-01 09:13', 73),
(1, '2017-01-01 09:14', 74),
(2, '2017-01-01 09:01', 70),
(2, '2017-01-01 09:02', 75),
(2, '2017-01-01 09:03', 80),
(2, '2017-01-01 09:04', 70),
(2, '2017-01-01 09:05', 72),
(2, '2017-01-01 09:06', 75),
(2, '2017-01-01 09:07', 60),
(2, '2017-01-01 09:08', 50),
(2, '2017-01-01 09:09', 52),
(2, '2017-01-01 09:10', 53),
(2, '2017-01-01 09:11', 65),
(2, '2017-01-01 09:12', 71),
(2, '2017-01-01 09:13', 73),
(2, '2017-01-01 09:14', 74),
(3, '2017-01-01 09:12', 71),
(3, '2017-01-01 09:13', 60),
(3, '2017-01-01 09:14', 74)

现在结合常用的 table 表达式,使用 Lead 和 Lag 查找前几行值,以确定这是一系列低血压的开始还是结束。使用开始事件和结束事件的 UNION 可确保将仅涵盖一分钟的事件同时记录为开始事件和结束事件。

;WITH CTE
AS
(
    SELECT *, 
        LAG(SystolicBloodPressure,1) 
            OVER (PaRTITION BY Patient_Id ORDER BY TimeStamp) As PrevValue, 
        Lead(SystolicBloodPressure,1) 
            OVER (PaRTITION BY Patient_Id ORDER BY TimeStamp) As NextValue  
    FROM #bloodpressure
),
CTE2
AS
(
    -- Get Start Events (EventType 1)
    SELECT 1 As [EventType],  Patient_id, TimeStamp,
          ROW_NUMBER() OVER (ORDER BY Patient_id, TimeStamp) AS RN
    FROM CTE
    WHERE (PrevValue IS NULL AND SystolicBloodPressure < 70) OR 
          (PrevValue >= 70 AND SystolicBloodPressure < 70)
    UNION
    -- Get End Events (EventType 2)
    SELECT 2 As [EventType],  Patient_id, TimeStamp, 
           ROW_NUMBER() OVER (ORDER BY Patient_id, TimeStamp) AS RN
    FROM CTE
    WHERE (NextValue IS NULL AND SystolicBloodPressure < 70 ) OR 
          (NextValue >= 70 AND SystolicBloodPressure < 70)
)
SELECT C1.Patient_id, C1.TimeStamp As EventStart, C2.TimeStamp As EventEnd 
FROM CTE2 C1
INNER JOIN CTE2 C2
    ON C1.Patient_id = C2.Patient_id AND C1.RN = C2.RN
WHERE C1.EventType = 1 AND C2.EventType = 2
ORDER BY C1.Patient_id, C1.TimeStamp