3

我有一个包含索引数据的表,每一行都有一个开始和结束时间。查询此表并获取时间跨度在总体时间段内(通常是从 00:00:00 到 23:59:59 的某一天)内的索引行列表很简单。

declare @date datetime, @start datetime, @end datetime

set @date = GetDate() //in production code this is a n input to a stored proc

//the date component of the current date/time, starting at midnight
set @start = DateAdd(dd, DateDiff(dd, 0, @date), 0) 

//one second before midnight the next day
set @end = DateAdd(dd, 1, DateAdd(ss, -1, @start)) 

select idx, start_time, end_time
from index_data
where start_time <= @end
and end_time >= @start
order by start_time 

结果将是这样的:

idx         start_time                  end_time
---------------------------------------------------------------
495640      2012-05-03 00:17:13.000     2012-05-03 00:17:45.000
495641      2012-05-03 00:18:20.000     2012-05-03 00:18:51.000
495642      2012-05-03 00:18:55.000     2012-05-03 00:19:31.000
495643      2012-05-03 00:34:08.000     2012-05-03 00:34:28.000
495644      2012-05-03 00:36:21.000     2012-05-03 00:36:41.000
495646      2012-05-03 01:22:21.000     2012-05-03 01:22:38.000
495647      2012-05-03 01:24:38.000     2012-05-03 01:24:55.000
495648      2012-05-03 01:30:11.000     2012-05-03 01:30:29.000
495649      2012-05-03 01:31:23.000     2012-05-03 01:31:39.000
495650      2012-05-03 02:09:57.000     2012-05-03 02:10:59.000
495651      2012-05-03 02:11:00.000     2012-05-03 02:11:00.000
495652      2012-05-03 02:14:25.000     2012-05-03 02:14:42.000
495653      2012-05-03 02:31:09.000     2012-05-03 02:31:25.000
495655      2012-05-03 03:02:32.000     2012-05-03 03:02:51.000
...

我需要的是一个有效的查询(没有游标或其他循环),它将生成一个结果集,为给定日期的每一小时和每一分钟提供一行,对于该行,该分钟的至少一秒属于至少一个索引的时间范围:

hour   min
----------
0      17
0      18
0      19
0      34
0      36
1      22
1      24
1      30
1      31
2      9
2      10
2      11
2      14
2      31
3      02
...

每个索引的 start_time 和 end_time 通常相隔不到 60 秒(因此每分钟产生几行,因此希望合并以节省网络带宽),但我不能保证;某些行可能跨越更长的时间段,例如 start_time 为 02:20:34,end_time 为 02:23:43。给定这样的跨度,结果集必须包括 2:20、2:21、2:22 和 2:23,您不会通过对 start_time 的查询与 end_time 的查询进行 UNION 来获得。

关键是:查询必须与 MSDE 引擎兼容,它基本上是 MSS 2000。所以,没有 CTE(或者我已经这样做了)。

4

1 回答 1

2

如果效率是指最小的 CPU 时间、读取次数等,那么您需要一个查找表。

创建一个包含一天中所有 1440 分钟作为 DATETIME 的表。

DECLARE
  @date  DATETIME,
  @start DATETIME,
  @end   DATETIME
SELECT
  @date  = GetDate(),
  @start = DateAdd(dd, DateDiff(dd, 0, @date), 0),
  @end   = DateAdd(dd, 1, @start)

SELECT
  minute_lookup.timestamp,
  COUNT(*)                    AS total_records
FROM
  index_data
INNER JOIN
  minute_lookup
    ON  minute_lookup.timestamp >= index_data.start_time - @date
    AND minute_lookup.timestamp <  index_data.end_time   - @date
WHERE
      index_data.start_time < @end
  AND index_data.end_time   > @start
GROUP BY
  minute_lookup.timestamp
ORDER BY
  minute_lookup.timestamp

实际上,您正在缓存一些计算。没有试图填补数据点之间的空白。


关于日期时间边界的旁白

另外,请注意我使用不同的开始结束值。

如果我想涵盖一整天,我不会2012-01-01 00:00:002012-01-01 23:59:59。如果表格在半秒后包含一个值怎么办?

DateTimes 并不是真正的离散值,它们是连续的。因此,我使用 FROM 2012-01-01 00:00:00upto,但不包括,2012-01-02 00:00:00

  • x >= '2012-01-01' AND x < '2012-01-02'

通过这种方式,无论 x 存储为什么级别的准确度,如果它代表 2012 年 1 月 1 日的任何内容,我都会捕获它。

于 2012-05-03T23:36:27.567 回答