确定条纹中的条纹和时间

时间:2018-01-16 15:22:36

标签: sql sql-server sql-server-2012

我有一个带有buildID(UUID,而不是int)的简单表,Repository,日期和结果:

BuildID     Repository  BuildDateTime         Result
------------------------------------------------------
1234        Repo1       2017-01-02T01:23:56   Fail
2224        Repo1       2017-01-02T01:22:56   Fail
3234        Repo1       2017-01-02T01:20:56   Success
4234        Repo2       2017-01-01T01:20:00   Fail
5234        Repo2       2017-01-01T01:19:00   Success
6234        Repo2       2017-01-01T01:18:00   Success
7234        Repo3       2017-01-01T01:17:30   Success
8234        Repo2       2017-01-01T01:17:00   Success

我想确定,对于每个构建,存储库的构建具有相同结果的行中连续构建的数量,以及它何时启动条纹。我想把它放到一个视图中,所以结果看起来像这样:

BuildID  Repository  BuildDateTime         Result   Streak   StreakStartDateTime
-------------------------------------------------------------------------------
1234     Repo1       2017-01-02T01:23:56   Fail     2        2017-01-02T01:22:56
2224     Repo1       2017-01-02T01:22:56   Fail     1        2017-01-02T01:22:56
3234     Repo1       2017-01-02T01:20:56   Success  1        2017-01-02T01:20:56
4234     Repo2       2017-01-01T01:20:00   Fail     1        2017-01-01T01:20:00
5234     Repo2       2017-01-01T01:19:00   Success  3        2017-01-01T01:17:00
6234     Repo2       2017-01-01T01:18:00   Success  2        2017-01-01T01:17:00 
7234     Repo3       2017-01-01T01:17:30   Success  1        2017-01-01T01:17:30
8234     Repo2       2017-01-01T01:17:00   Success  1        2017-01-01T01:17:00

我一直在使用滞后函数,这有助于我理解之前的X行。问题是我需要返回以查找结果的行数因行而异。我开始认为这是一个死胡同。

感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

可以使用lag完成此操作。

select t.*
,row_number() over(partition by repository,grp order by buildDatetime) as streak
,min(buildDatetime) over(partition by repository,grp) as streakStartDatetime
from (select t.*
     ,sum(prev_same_or_not) over(partition by repository order by buildDatetime) as grp
      from (select t.*  
            ,case when lag(result) over(partition by repository order by buildDatetime) = result then 0 else 1 end as prev_same_or_not
            from tbl t
           ) t
     ) t

看起来势不可挡,但这是如何运作的。

  1. 检查前一行是否与当前行具有相同的结果,并相应地指定一个标志。
  2. 使用运行总和将具有相同值的连续结果分类到同一组中。
  3. 获取每组的最小日期时间,并使用行号根据组计算条纹。

答案 1 :(得分:1)

这是另一种做法。基本上为每个构建在历史记录中分配一个订单,并在历史记录中查找最早的一个订单,它们具有相同的状态,并且两者之间没有任何状态。

WITH CTE_Builds AS (
    SELECT *
    , RN = ROW_NUMBER() OVER (PARTITION BY Repository ORDER BY BuildDateTime)
    FROM BuildHistory
)
SELECT a.*
, Streak = ISNULL(a.RN - x.MIN_RN,0) + 1
, StreakStartDateTime = ISNULL(x.MIN_DATE, a.BuildDateTime)
FROM CTE_Builds a
OUTER APPLY (
    SELECT MIN_RN = MIN(RN),  MIN_DATE = MIN(BuildDateTime)
    FROM CTE_Builds b
    WHERE b.Repository = a.Repository
      AND b.RN < a.RN
      AND b.Result = a.Result
      AND NOT EXISTS (
        SELECT *
        FROM CTE_Builds c
        WHERE c.Repository = b.Repository
          AND c.RN BETWEEN b.RN and a.RN
          AND c.Result != b.Result
        )
    ) x
ORDER BY a.Repository, a.BuildDateTime DESC