对时间序列数据中的特定状态更改进行分组

时间:2013-07-08 08:06:08

标签: sql-server tsql group-by time-series

我有一个表每秒接收一行,每秒一个活动状态与时间戳一起传递。我需要根据状态的特定变化进行分组,例如当状态从6变为0然后全部跟随0之后再直到状态变化。 解释这个问题的最好方法就是一个例子:

| TimeStamp |国家|

| 13:05:00 | 1 |
| 13:05:05 | 0 |
| 13:05:10 | 0 |
| 13:05:15 | 6 |
| 13:05:20 | 6 |
| 13:05:25 | 0 |
| 13:05:30 | 0 |
| 13:05:35 | 6 |
| 13:05:40 | 6 |
| 13:05:45 | 0 |
| 13:05:50 | 0 |

我希望从这个表中得到的结果是2组,(状态从6到0有2个变化)将所有状态为6的状态分组,直到状态再次变化。 δ13​​:05:25,13:05:30取代;δ13:05:45,13:05:50为烷基;

2 个答案:

答案 0 :(得分:1)

    CREATE TABLE MyTable
    (
      [TimeStamp] NVARCHAR(10),
      [State] INT
    )

    INSERT INTO MyTable ([TimeStamp], [State])
    SELECT '13:05:00', 1
    UNION ALL
    SELECT '13:05:05', 0
    UNION ALL
    SELECT '13:05:10', 0
    UNION ALL
    SELECT '13:05:15', 6
    UNION ALL
    SELECT '13:05:20', 6
    UNION ALL
    SELECT '13:05:25', 0
    UNION ALL
    SELECT '13:05:30', 0
    UNION ALL
    SELECT '13:05:35', 6
    UNION ALL
    SELECT '13:05:40', 6
    UNION ALL
    SELECT '13:05:45', 0
    UNION ALL
    SELECT '13:05:50', 0
    GO

;WITH cte( [RowNum], [TimeStamp], [State]) AS
(
  SELECT ROW_NUMBER() OVER(ORDER BY TIMESTAMP), TIMESTAMP, STATE FROM MyTable
)
SELECT 
t2.TimeStamp AS [Start],
ISNULL
(
  (SELECT TimeStamp FROM cte WHERE RowNum = (SELECT TOP 1 RowNum FROM cte WHERE State <> 0 AND RowNum > t2.RowNum ORDER BY TimeStamp)-1)
  ,(SELECT MAX(TimeStamp) FROM cte)
) [End]
FROM cte t1
JOIN cte t2 ON t1.RowNum = t2.RowNum - 1
WHERE t1.State = 6 AND t2.State = 0
GO

try in Fiddle

答案 1 :(得分:0)

不确定问题是否足够清楚:|所以我以另一种方式接近它,因为找到从6到0的第一个变化很容易做到:

with x as (
  select *, rn = ROW_NUMBER() OVER (ORDER BY Activity_Time)
  FROM WellData_Activity
  )
  Select x.Activity_Code, x.Activity_Time
  from x left outer join x as y
  on x.rn = y.rn + 1
  and x.Activity_Code <> y.Activity_Code
  where y.activity_code is not null

但是一系列activity_codes的分组更难以同时完成,所以我用它首先对它们进行分组(按时间顺序按activity_code)然后我可以运行第一个查询来返回一行(现在返回开始/结束):

WITH periods AS (
SELECT
    *,
    grp = ROW_NUMBER() OVER (PARTITION BY Well_GUID        ORDER BY Activity_Time)
    - ROW_NUMBER() OVER (PARTITION BY Well_GUID, Activity_Code ORDER BY Activity_Time)
  FROM WellData_Activity
)
SELECT
  Well_GUID,
  date_from = MIN(Activity_Time),
  date_to   = MAX(Activity_Time),
  Activity_Code
FROM periods
GROUP BY
Well_GUID,
Activity_Code,
grp
ORDER BY
Well_GUID,
MIN(Activity_Time)