【问题标题】:SQL list periodes where value is more then a spesific valueSQL 列出值大于特定值的期间
【发布时间】:2015-09-02 01:38:51
【问题描述】:

我有一个像这样的表 Id、DateTime、Device、Value。 我需要找到 Value >=5 的所有时段,并为这些时段返回 From 和 To dateTime。 设备可以是温度传感器,我需要温度超过 5 的 From/To 列表。

如果我们认为它是一个温度传感器并且它每 5 分钟记录一次。表格将是这样的:

Id DateTime         Device Value
--------------------------------
1  2015.09.01 09:10  T1     3,2 
2  2015.09.01 09:15  T1     5,2 
3  2015.09.01 09:20  T1     6,2 
4  2015.09.01 09:25  T1     5,8 
5  2015.09.01 09:30  T1     3,2 
6  2015.09.01 09:35  T1     1,2 
7  2015.09.01 09:40  T1     5,6 
8  2015.09.01 09:45  T1     6,1 
9  2015.09.01 09:50  T1     5,0 
10 2015.09.01 09:55  T1     2,0 

我试图找到的时段是从 09:15 到 09:25 以及从 09:40 到 09:50。

在 SQL Server 2014 中是否有一种智能的方法来执行此操作?

【问题讨论】:

  • 如果您能提供一些示例数据以及所需的结果集,将会很有帮助。
  • 我不知道从哪里开始。我想我必须找到 value>=5 的所有记录,然后我必须找到 value >=5 但没有任何记录的最后一条记录具有情人值。
  • 如果我们认为它是一个温度传感器并且它每 5 分钟记录一次。表格将是这样的。 1. 2015.09.01 09:10 T1 3,2 2. 2015.09.01 09:15 T1 5,2 3. 2015.09.01 09:20 T1 6,2 4. 2015.09.01 09:25 T1 5,8 5. 2015.09.01 09:30 T1 3,2 6. 2015.09.01 09:35 T1 1,2 7. 2015.09.01 09:40 T1 5,6 8. 2015.09.01 09:45 T1 6,1 9. 2015.09. 01 09:50 T1 5,0 10. 2015.09.01 09:55 T1 2,0 我试图找到的时间段是从 09:15 到 09:25 以及从 09:40 到 09:50。
  • 如果我正确理解了这个问题,您有一个经常记录温度的表格,并且您希望获得一个温度不低于 5 度的时间段的结果集。为此,您需要按日期对表格进行排序,按温度高于 5 度的记录分组,并为每个组选择 MIN 和 MAX 日期。确实是个不错的问题!
  • 是的,我想你现在开始我需要的东西了:),我喜欢你的想法,但我想我只会得到 1 个结果作为回报?一天中可能有 5 次温度超过 5 度,我需要找到所有这些时期。结果集是 5 条记录,每次温度超过 5 度时的开始和结束时间。 (对不起我的英文写得不太好)

标签: sql-server sql-server-2014


【解决方案1】:

这是获得所需结果的一种方式:

SELECT MIN([DateTime]) AS StartPeriod, MAX([DateTime]) AS EndPeriod,
       Device
FROM (       
SELECT Id, [DateTime], Device, Value,
       ROW_NUMBER() OVER (PARTITION BY Device ORDER BY Id) -
       COUNT(CASE WHEN Value >= 5 THEN 1 END) 
       OVER (PARTITION BY Device ORDER BY Id) AS grp
FROM mytable ) AS t
WHERE t.Value >= 5
GROUP BY Device, grp

如果您想每天获得Start - End 经期,您可能需要PARTITION BY Device, [DateTime]

Demo here

【讨论】:

  • 谢谢,Giorgos Betsos :)
【解决方案2】:

是的,有一个聪明的方法可以做到这一点。

看看“PARTITION BY”和“OVER”子句。

使用这些功能,我相信您应该能够按时间段对数据进行分区(分组)并获取每个组的 DateTime 列的 MIN 和 MAX 值。

【讨论】:

    【解决方案3】:

    这基本上是answered before,诀窍是您已经连续连续地订购了id 列。如果这不存在,您需要做更多的前期工作才能使减法正常工作。

    select * into #tempTable from (
    select Id = 1,[DateTime] = cast('2015.09.01 09:10' as datetime), device = 'T1', value = 3.2
    union all select 2,cast('2015.09.01 09:15' as datetime),'T1',5.2
    union all select 3,cast('2015.09.01 09:20' as datetime),'T1',6.2
    union all select 4,cast('2015.09.01 09:25' as datetime),'T1',5.8
    union all select 5,cast('2015.09.01 09:30' as datetime),'T1',3.2
    union all select 6,cast('2015.09.01 09:35' as datetime),'T1',1.2
    union all select 7,cast('2015.09.01 09:40' as datetime),'T1',5.6
    union all select 8,cast('2015.09.01 09:45' as datetime),'T1',6.1
    union all select 9,cast('2015.09.01 09:50' as datetime),'T1',5
    union all select 10,cast('2015.09.01 09:55' as datetime),'T1',2) A
    
    
    with T as (select *, row_number() over (order by id) - id as grp
        from #tempTable
        where value >=5
        )
    select [to] = min(T.Datetime), [from] =  max(T.DateTime) 
    from T
    group by T.grp
    order by T.grp
    

    输出为

    to                        from
    2015-09-01 09:40:00.000   2015-09-01 09:50:00.000
    2015-09-01 09:15:00.000   2015-09-01 09:25:00.000
    

    (我必须进行一些转换才能使您的数字/日期格式适合我)

    【讨论】:

      【解决方案4】:

      我一直在使用一个表用户定义的函数,该函数在参数中接受请求的日期,函数内的光标允许填充返回的表,如下所示:

      CREATE TABLE sensor (id int not null identity(1,1) primary key, 
          measureDate datetime, sensor nvarchar(10), measure float)
      
      INSERT sensor (measureDate, sensor, measure) VALUES
      ('2015-09-01 09:10', 'T1', '3.2'), ('2015-09-01 09:15', 'T1', '5.2'),
      ('2015-09-01 09:20', 'T1', '6.2'), ('2015-09-01 09:25', 'T1', '5.8'),
      ('2015-09-01 09:30', 'T1', '3.2'), ('2015-09-01 09:35', 'T1', '1.2'),
      ('2015-09-01 09:40', 'T1', '5.6'), ('2015-09-01 09:45', 'T1', '6.1'),
      ('2015-09-01 09:50', 'T1', '5.0'), ('2015-09-01 09:55', 'T1', '2.0')
      GO
      CREATE FUNCTION [dbo].[getTimeSpansBelowMaxTemp] (@measureDate date) 
          RETURNS @timeSpans TABLE (fromTime time, toTime time) AS BEGIN
      
          DECLARE @measure float, @currentMeasure float = NULL
          DECLARE @measureTime time, @fromMeasureTime time, @toMeasureTime time
          DECLARE yourCursor CURSOR FOR
          SELECT CAST(measureDate AS time), measure 
              FROM sensor
                  WHERE CAST(measureDate as date) = @measureDate
          OPEN yourCursor
          FETCH NEXT FROM yourCursor INTO @measureTime, @measure
          WHILE (@@FETCH_STATUS = 0) BEGIN -- Loops on all the measures of the given day
              IF @measure >= 5.0 BEGIN
                      IF @currentMeasure IS NULL BEGIN -- Start of a period
                          SET @currentMeasure = @measure
                          SET @fromMeasureTime = @measureTime
                      END
                      SET @toMeasureTime = @measureTime
              END
              ELSE BEGIN
                      IF @currentMeasure IS NOT NULL BEGIN -- End of a period
                          INSERT INTO @timeSpans VALUES (@fromMeasureTime, @toMeasureTime)
                          SET @currentMeasure = NULL
                      END
              END 
              FETCH NEXT FROM yourCursor INTO @measureTime, @measure
          END
      
          CLOSE yourCursor
          DEALLOCATE yourCursor
      
          RETURN
      END
      GO
      
      select * from dbo.[getTimeSpansBelowMaxTemp]('2015-09-01')
      

      【讨论】:

        猜你喜欢
        • 2014-04-24
        • 1970-01-01
        • 2018-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-23
        相关资源
        最近更新 更多