SQL从周围的行创建表

时间:2014-06-11 23:16:01

标签: sql tsql

我有一个数据库表('map'),其中包含以下列:

  • ptID(唯一识别患者)
  • uniid(uniqueidentifier for every ())
  • 时间(每1分钟换一行)
  • mapval(感兴趣的数据点)
  • 验证(0或1)

我想要的是每次验证= 1时前后30个mapval的表。这61行应来自表'map'并包含所有行(即当validate = 0或1时,不仅仅是1 )。

我尝试使用lag / lead进行查询,但没有运气。

仅供参考,一旦我有了这张桌子,我就打算对数据做一些基本的事情。像平均值,中位数(带有percentile_cont)和模式(带有有序计数)。

此时我可以使用以下内容轻松地使用表格执行AVG:

 SELECT [ptID],[time],[mapval],[validate],
    IIF([validate]=1,   
      AVG(CAST ([mapval] AS decimal)) 
       OVER(
         PARTITION BY [ptID]
         ORDER BY [ptID] ASC, [time] ASC
         ROWS BETWEEN 30 PRECEDING AND 30 FOLLOWING 
            ) 
      ,NULL) AS 'sixytminavg'

但遗憾的是不能做中位数或模式。

龙卷风,但我希望它能提供所有信息。提前谢谢!

3 个答案:

答案 0 :(得分:0)

在我的头顶,可能是以下情况?

SELECT m.ptid, m.uniid, m.time, m.mapval, m.validate
FROM map m INNER JOIN 
(SELECT uniid
FROM map
WHERE validate=1) AS valids ON m.uniid BETWEEN valids.uniid-30 AND valids.uniid+30
ORDER BY m.uniid

答案 1 :(得分:0)

让我专注于此:

  

我想要的是一张包含前后30的表格   mapval每次验证= 1.这61行应来自   表'map'并包括所有行(即,当validate = 0或1时,不是   只是1)。

每次验证后都可以获得30行 - 假设没有其他验证 - 将行分成组。我们的想法是为每一行分配一个验证组。并且,您可以通过计算每行之前验证次数为1的次数来完成此操作。然后取前31行:

select m.*
from (select m.*, row_number() over (partition by grp order by time) as seqnum
      from (select m.*, sum(validate) over (order by ptId order by time) as grp
            from map m
           ) m
     ) m
where seqnum <= 31;

您可以同时为小组之前和之后执行此操作:

select m.*
from (select m.*,
             row_number() over (partition by grp order by time) as seqnum_after,
             row_number() over (partition by grp order by time desc) as seqnum_before
      from (select m.*,
                   sum(validate) over (order by ptId order by time) as grp_after,
                   sum(validate) over (order by ptId order by time desc) as grp_before
            from map m
           ) m
     ) m
where seqnum_after <= 31 or seqnum_before <= 31;

编辑:

如果验证距离太近,则使用join方法代替:

select m.*
from (select m.*, row_number() over (partition by ptid order by time) as seqnum
      from map m
      where validate = 1
     ) v join
     (select m.*, row_number() over (partition by ptid order by time) as seqnum
      from map m
     ) m
     on v.ptid = m.ptid and m.seqnum between v.seqnum - 30 and v.seqnum + 30;

答案 2 :(得分:0)

感谢@Gordon的解决方案。唯一的问题是第一个选择将row_numbers限制为那些经过验证的行,而不是对所有行进行编号并选择已验证的行。我已经添加了另一个嵌套select来实现它。不是最快的查询,但我只需要在我们的数据集上运行几次。

select q.*, n.time rowtime, n.mapval rowmapval 
    from ( select v.* 
        from (
             select m.*, row_number() over (partition by ptid order by time) as seqnum
             from map m
             ) v
        where validate = 1
        ) q
    join
        (select m.*, row_number() over (partition by ptid order by time) as seqnum
        from map m
        ) n
    on q.ptid = n.ptid and n.seqnum between q.seqnum - 30 and q.seqnum + 30
        ORDER by q.ptID, q.time, n.time