SQL Server剧集标识

时间:2017-03-16 10:39:42

标签: sql sql-server threshold

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

我的目标是找到:

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

    一集由时间图组成,其中患者降至某个阈值以下,直至患者超过阈值的时间戳。

  2. 每位患者每次平均血压

  3. 每位患者每集的剧集持续时间

  4. 到目前为止我尝试过:

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

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

    但是,我无法“识别”患者体内的不同情节;第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
    

2 个答案:

答案 0 :(得分:1)

感谢您提供样本数据。

这应该有效:

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

答案 1 :(得分:0)

此答案依赖于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)

现在使用Lead And 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