Detect Anomaly Intervals with SQL

后端 未结 4 1255
猫巷女王i
猫巷女王i 2021-02-06 11:26

My problem is simple: I have a table with a series of statuses and timestamps (for the sake of curiosity, these statuses indicate alarm levels) and I would like to query this ta

相关标签:
4条回答
  • 2021-02-06 12:07

    This has to be one of the harder questions I've seen today - thanks! I assume you can use CTEs? If so, try something like this:

    ;WITH Filtered
    AS
    (
        SELECT ROW_NUMBER() OVER (ORDER BY dateField) RN, dateField, Status
        FROM Test    
    )
    SELECT F1.RN, F3.MinRN,
        F1.dateField StartDate,
        F2.dateField Enddate
    FROM Filtered      F1, Filtered F2, (
    SELECT F1a.RN, MIN(F3a.RN) as MinRN
    FROM Filtered      F1a
       JOIN Filtered F2a ON F1a.RN = F2a.RN+1 AND F1a.Status = 2 AND F2a.Status <> 2
       JOIN Filtered F3a ON F1a.RN < F3a.RN AND F3a.Status <> 2
    GROUP BY F1a.RN ) F3 
    WHERE F1.RN = F3.RN AND F2.RN = F3.MinRN
    

    And the Fiddle. I didn't add the intervals, but I imagine you can handle that part from here.

    Good luck.

    0 讨论(0)
  • 2021-02-06 12:15

    I do something similar by using id that is an identity to the table.

        create table test(id int primary key identity(1,1),timstamp datetime,val int)
    
        insert into test(timstamp,val) Values('1/1/2013 00:00:00',1)
        insert into test(timstamp,val) Values('1/1/2013 00:00:05',2)
        insert into test(timstamp,val) Values('1/1/2013 00:00:25',1)
        insert into test(timstamp,val) Values('1/1/2013 00:00:30',2)
        insert into test(timstamp,val) Values('1/1/2013 00:00:35',1)
    
        select t1.timstamp,t1.val,DATEDIFF(s,t1.timstamp,t2.timstamp) 
        from test t1 left join test t2 on t1.id=t2.id-1
    
        drop table test
    

    I would also make the timestamps be seconds since 1980 or 2000 or whatever. But then you might not want to do the reverse conversion all the time and so it depends on how often you use the actual time stamp.

    0 讨论(0)
  • 2021-02-06 12:19

    Just for the sake of having an alternative. Tried to do some test on performance, but did not finish.

    SELECT
      MIN([main].[Start]) AS [Start],
      [main].[End],
      DATEDIFF(s, MIN([main].[Start]), [main].[End]) AS [Seconds]
    FROM
    (
      SELECT
        [sub].[Start],
        MIN([sub].[End]) AS [End]
      FROM
      (
        SELECT
          [start].[Timestamp] AS [Start],
          [start].[Status] AS [StartingStatus],
          [end].[Timestamp] AS [End],
          [end].[Status] AS [EndingStatus]
        FROM [Alerts] [start],  [Alerts] [end]
        WHERE [start].[Status] = 2 
          AND [start].[Timestamp] < [end].[Timestamp]
          AND [start].[Status] <> [end].[Status]
      ) AS [sub]
      GROUP BY
        [sub].[Start],
        [sub].[StartingStatus]
    ) AS [main]
    GROUP BY
      [main].[End]
    

    And here is a Fiddle.

    0 讨论(0)
  • 2021-02-06 12:21

    Finally figured out a version I was happy with. It took me remembering an answer from another question (can't remember which one though) where it was pointed out that the difference between two (increasing) sequences was always a constant.

    WITH Ordered (occurredAt, status, row, grp) 
                 as (SELECT occurredAt, status, 
                            ROW_NUMBER() OVER (ORDER BY occurredat), 
                            ROW_NUMBER() OVER (PARTITION BY status 
                                               ORDER BY occurredat)
                     FROM Alert)
    
    SELECT Event.startDate, Ending.occurredAt as endDate,
           DATEDIFF(second, Event.startDate, Ending.occurredAt) as interval
    
    FROM (SELECT MIN(occurredAt) as startDate, MAX(row) as ending
          FROM Ordered
          WHERE status = 2
          GROUP BY row - grp) Event
    
    LEFT JOIN (SELECT occurredAt, row
               FROM Ordered
               WHERE status != 2) Ending
            ON Event.ending + 1 = Ending.row
    

    (working SQL Fiddle example, with some additional data rows for work checking).

    This unfortunately doesn't correctly deal with level-2 statuses that are end rows (behavior unspecified), although it does list them.

    0 讨论(0)
提交回复
热议问题