【问题标题】:SQL Server episode identificationSQL Server 剧集标识
【发布时间】:2017-03-16 10:39:41
【问题描述】:

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

我的目标是找到:

  1. 患者低于某个血压阈值的发作次数

    一个情节由患者下降到某个阈值以下的时间图组成,直到患者超过阈值的时间戳。

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

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

到目前为止我所尝试的:

如果达到阈值,我只需创建一个设置为 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

【问题讨论】:

  • 我建议你删除这个问题。然后问关于第一个项目的另一个问题,以及样本数据和期望的结果。正如所写,这对于单个“问题”来说相当广泛。
  • 我不认为它太宽泛,它可能都是一个单一的查询。无需创建新问题,但您绝对应该提供架构、示例数据等。
  • 我包含了样本数据。如果您需要更多信息,请随时询问!
  • 看起来像gaps-and-islands。最佳查询取决于 SQL Server 的版本。

标签: sql sql-server threshold


【解决方案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

【讨论】:

  • 非常感谢!它似乎适用于样本数据。但是,我刚开始使用 SQL,无法让它与我自己的表一起使用。你能在你的代码中添加一些关于你已经完成的 cmets 吗?并给出一些建议如何用自己的表来实现代码?
  • 根据您发布的内容,这就是我所能做的。请添加一些更相关和更接近现实的架构和数据。
  • 效果很好,但还有一个小问题。我想在“剧集列”中有每人的剧集编号。目前 person1 有第 1 集,第 2 个人有第 2 和 3 集,而我希望第 2 个人有第 1 集重新开始,所以 1 和 2.
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 2021-08-03
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多