Sql-获取特定条件下的百万+行的时间范围

时间:2018-05-31 11:13:13

标签: sql-server sql-server-2012 gaps-and-islands

我正在使用SQL Server 2012,我有一个包含大约35列和1000多万行的表。 我需要从数据中找到任何特定列的值匹配的时间范围 例如。 样本数据如下

 Datetime        col1  col2  col3
2018-05-31 0:00     1   2   1 
2018-05-31 13:00    2   2   2
2018-05-31 14:30    3   2   1
2018-05-31 15:00    4   3   1
2018-05-31 16:00    4   5   1
2018-05-31 17:00    3   2   2
2018-05-31 17:30    3   2   4
2018-05-31 18:00    2   2   4
2018-05-31 20:00    1   2   6
2018-05-31 21:00    2   2   3
2018-05-31 21:10    2   2   1
2018-05-31 22:00    1   6   3
2018-05-31 22:00    4   5   1
2018-05-31 23:59    4   7   2

从数据中查找时间范围,其中col2值=< 2,因此我的预期结果集如下

Start Time           End time           Time Diff
2018-05-31 0:00     2018-05-31 14:30    14:30:00
2018-05-31 17:00    2018-05-31 21:10    4:10:00

我可以用以下逻辑实现相同,但它非常慢 我得到所有行然后

  1. 按日期排序

  2. 扫描行获取准确值匹配的第一行,并将该时间戳记录为开始时间。

  3. 扫描更多行,直到我得到条件正在中断的行,并将该时间戳记录为结束时间。

  4. 但是因为我必须玩很大的没有。行,总体来说这会使我的操作变慢,任何输入或伪代码都会改进。

1 个答案:

答案 0 :(得分:1)

我们可以在这里使用行数方法略微修改的差异。标记为cte1的第一个CTE的目的是添加一个计算列,该列标记我们想要的岛,col2值<= 2,为1,其他所有为0.然后,我们可以计算两个行数的差异,并在岛上聚合以查找起始和结束时间,以及这些时间之间的差异。

WITH cte1 AS (
    SELECT *,
        CASE WHEN col2 <= 2 THEN 1 ELSE 0 END AS class
    FROM yourTable
),
cte2 AS (
    SELECT *,
        ROW_NUMBER() OVER (ORDER BY Datetime) -
        ROW_NUMBER() OVER (PARTITION BY class ORDER BY Datetime) rn
    FROM cte1
)

SELECT
    MIN(Datetime) AS [Start Time],
    MAX(Datetime) AS [End Time],
    CONVERT(TIME, MAX(Datetime) - MIN(Datetime)) AS [Time Diff]
FROM cte2
WHERE class = 1
GROUP BY rn
ORDER BY MIN(Datetime);

enter image description here

Demo