2

我有一张 StartTimes 和 EndTimes 表

我想在每个开始时间和结束时间之间每 15 分钟增量将它们分成 1 行。

就像是

SELECT StartTime, DATEDIFF(mi, StartTime, EndTime) / 15 AS Offset FROM myTable
CROSS APPLY
-- put something in here to split each row into (EndTime - StartTime) / 15 rows

我想我可以为此使用 SQL OVER 函数……但我不知道该怎么做。

4

2 回答 2

1

在您需要生成不存在的行的情况下,创建一个数字表会很有帮助,该表仅包含一组编号为 1、2、3 等的行。例如,这将创建一个表从 0 到 99 的数字:

create table ids ( id int )

declare @id int
set @id = 0
while @id < 100
begin
    insert ids values (@id)
    set @id = @id + 1
end

然后在这个数字表上构建,就像与原始表连接在一起一样简单,并且限制基于id小于生成的 15 分钟周期数:

select
  DATEADD(mi, id * 15, StartTime) AS StartTime,
  DATEADD(mi, (id + 1) * 15, StartTime) AS EndTime
from
  MyTable T
join
  ids I on I.id < DATEDIFF(mi, StartTime, EndTime) / 15

请注意,上述查询做了两个假设:

  • 您所有的 StartTime - EndTime 组合都具有可被 15 整除的差异。
  • 您的 StartTime - EndTime 对都不会跨越超过一百个 15 分钟周期的范围(如果是这样,您只需要使ids表格更大)。

演示:http ://www.sqlfiddle.com/#!6/595a9

于 2013-01-19T02:11:34.573 回答
1

您还可以为此使用递归 CTE 以避免创建辅助表:

WITH "CTE"
AS
(
  SELECT "id", "starttime" FROM "data"
  UNION ALL
  SELECT "id", DATEADD( MINUTE, 15, "starttime" )
  FROM "CTE"
  WHERE "starttime" < ( SELECT "endtime" FROM "data" AS D2 WHERE D2."id" = CTE."id" )
)
SELECT * FROM "CTE" 
ORDER BY "ID"

请参阅SQL-Fiddle-Demo

上述查询还假设数据表中的开始时间和结束时间组合的差异可以被 15 整除。

我已经编辑了查询以使用不能被 15 整除的日期时间 - 如果您选择的 15 分钟间隔不适合最后计算的间隔,它将被拒绝:

WITH "CTE"
AS
(
  SELECT "id", "starttime" FROM "data"
  UNION ALL
  SELECT "id", DATEADD( MINUTE, 15, "starttime" )
  FROM "CTE"
  WHERE "starttime" <= ( SELECT DATEADD( MINUTE, -15, "endtime" ) FROM "data" AS D2 WHERE D2."id" = CTE."id" )
)
SELECT * FROM "CTE" 
ORDER BY "ID"

如果您想在结果中拒绝最后一个时间戳(在 fiddle-demo 中id 2, timestamp "12:00:00"),只需更改<=<. 如果您正在使用半开区间,这也将是相关的。

请参阅已编辑的 SQL-Fiddle-Demo

于 2013-01-19T10:11:09.010 回答