按日期获取状态计数,但仅统计连续行

时间:2018-09-11 15:19:17

标签: sql-server date sql-server-2016 continuous

我有此数据:

ID  Name        Status  Date
1   Machine1    Active  2018-01-01
2   Machine2    Fault   2018-01-01
3   Machine3    Active  2018-01-01
4   Machine1    Fault   2018-01-02
5   Machine2    Active  2018-01-02
6   Machine3    Active  2018-01-02
7   Machine2    Active  2018-01-03
8   Machine1    Fault   2018-01-03
9   Machine2    Active  2018-01-04
10  Machine1    Fault   2018-01-04
11  Machine3    Active  2018-01-06

输入

我想要这些数据输出

预期输出

Name           Last Status  Count
Machine1         Fault       3  
Machine2         Active      3  
Machine3         Active      1       Because Date is not Continuous

* Count:连续历史记录中的最后一个状态

2 个答案:

答案 0 :(得分:0)

尽管SQLFiddle目前适合,但我认为这会起作用,所以我无法测试:

SELECT [Name], [Status], ct as [Count]
FROM (
 SELECT 
  [name], 
  [status], 
  [date],
  1 + (SUM( grp ) OVER (PARTITION BY [name], [status] ORDER BY [date] ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING ) * grp) ct,
  row_number() over(partition by [name] order by [date] desc) rn
 FROM
 (
  SELECT *, CASE WHEN LAG([Date]) OVER(PARTITION BY [name], [status] ORDER BY [date] ) = DATEADD(day, -1, [date]) THEN 1 ELSE 0 END grp
  FROM t
 ) x
) y
WHERE
  rn = 1

首先使用LAG查看当前行和上一行(将数据分组为计算机名称和状态,并按日期对数据进行排序),如果当前日期与上一日期不同1天,则会记录一个1否则为0

这些1和0以连续总计的方式求和,在计算机名称或状态更改时重置(sum()over()的分区)

我们还希望仅根据计算机名称来考虑数据,并且只希望每台计算机上的最新记录,因此我们按计算机名称进行分区,并按日期降序计数,然后选择(用where子句)每台计算机上编号为1的行

如果像这样单独运行查询,实际上会更有意义

计算“对于给定的状态和机器,当前报告是否与上一个报告连续” 1 =是,0 =否:

SELECT *, CASE WHEN LAG([Date]) OVER(PARTITION BY [name], [status] ORDER BY [date] ) = DATEADD(day, -1, [date]) THEN 1 ELSE 0 END grp
  FROM t

计算“连续报告的当前块的总运行量”:

SELECT 
  [name], 
  [status], 
  [date],
  1 + (SUM( grp ) OVER (PARTITION BY [name], [status] ORDER BY [date] ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING ) * grp) ct,
  row_number() over(partition by [name] order by [date] desc) rn
 FROM
 (
  SELECT *, CASE WHEN LAG([Date]) OVER(PARTITION BY [name], [status] ORDER BY [date] ) = DATEADD(day, -1, [date]) THEN 1 ELSE 0 END grp
  FROM t
 ) x

然后,整个过程,但是没有where子句,因此您可以看到我们正在丢弃的数据:

SELECT [Name], [Status], ct as [Count]
FROM (
 SELECT 
  [name], 
  [status], 
  [date],
  1 + (SUM( grp ) OVER (PARTITION BY [name], [status] ORDER BY [date] ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING ) * grp) ct,
  row_number() over(partition by [name] order by [date] desc) rn
 FROM
 (
  SELECT *, CASE WHEN LAG([Date]) OVER(PARTITION BY [name], [status] ORDER BY [date] ) = DATEADD(day, -1, [date]) THEN 1 ELSE 0 END grp
  FROM t
 ) x
) y

小提琴终于醒了:

http://www.sqlfiddle.com/#!18/77dae/2

答案 1 :(得分:0)

我相信它是如此简单:

WITH cte1 AS (
    SELECT
        Name,
        Status,
        DATEADD(DAY, ROW_NUMBER() OVER (PARTITION BY Name, Status ORDER BY Date DESC) - 1, Date) AS GroupingDate
    FROM testdata
), cte2 AS (
    SELECT
        Name,
        Status,
        RANK() OVER (PARTITION BY Name ORDER BY GroupingDate DESC) AS GroupingNumber
    FROM cte1
)
SELECT Name, Status AS LastStatus, COUNT(*) AS LastStatusCount
FROM cte2
WHERE GroupingNumber = 1
GROUP BY Name, Status
ORDER BY Name

Result and DBFiddle

| Name     | LastStatus | LastStatusCount |
|----------|------------|-----------------|
| Machine1 | Fault      | 3               |
| Machine2 | Active     | 3               |
| Machine3 | Active     | 1               |

为了了解其工作原理,请查看CTE生成的中间值:

| Name     | Status | Date                | RowNumber | GroupingDate        | GroupingNumber |
|----------|--------|---------------------|-----------|---------------------|----------------|
| Machine1 | Fault  | 04/01/2018 00:00:00 | 1         | 04/01/2018 00:00:00 | 1              |
| Machine1 | Fault  | 03/01/2018 00:00:00 | 2         | 04/01/2018 00:00:00 | 1              |
| Machine1 | Fault  | 02/01/2018 00:00:00 | 3         | 04/01/2018 00:00:00 | 1              |
| Machine1 | Active | 01/01/2018 00:00:00 | 1         | 01/01/2018 00:00:00 | 4              |
| Machine2 | Active | 04/01/2018 00:00:00 | 1         | 04/01/2018 00:00:00 | 1              |
| Machine2 | Active | 03/01/2018 00:00:00 | 2         | 04/01/2018 00:00:00 | 1              |
| Machine2 | Active | 02/01/2018 00:00:00 | 3         | 04/01/2018 00:00:00 | 1              |
| Machine2 | Fault  | 01/01/2018 00:00:00 | 1         | 01/01/2018 00:00:00 | 4              |
| Machine3 | Active | 06/01/2018 00:00:00 | 1         | 06/01/2018 00:00:00 | 1              |
| Machine3 | Active | 02/01/2018 00:00:00 | 2         | 03/01/2018 00:00:00 | 2              |
| Machine3 | Active | 01/01/2018 00:00:00 | 3         | 03/01/2018 00:00:00 | 2              |

这里的窍门是,如果两个数字是连续的,那么从它们中减去连续的数字将得到相同的值。例如。如果我们有5, 6, 8, 9,则按该顺序减去1, 2, 3, 4将产生4, 4, 5, 5