使用 SQL Server 2012 生成包含一天中各小时的日历表

问题描述 投票:0回答:4

问题陈述: 我在消防部门工作,正在对我的数据进行统计分析。一个问题是生成一个日历年中每天每小时的服务呼叫数量。我需要一张可以连接到一年中每一天和每天每小时的火灾事件的表。我希望的是以下内容(使用军事时间)

2017 年 1 月 1 日 00:00:00

2017 年 1 月 1 日 00:00:00

2017 年 1 月 1 日 01:00:00

2017 年 1 月 1 日 02:00:00

2017 年 1 月 1 日 03:00:00

2017 年 1 月 1 日 04:00:00

2017 年 1 月 1 日 05:00:00

2017 年 1 月 1 日 06:00:00

2017 年 1 月 1 日 07:00:00

2017 年 1 月 1 日 08:00:00

等等直到年底

2017年12月31日21:00:00

2017年12月31日22:00:00

2017年12月31日23:00:00

年底

此表将允许我加入火灾事故表,我将能够统计计算一天中每一小时和一年中每一天的事故数量。计算表是必要的,因为火灾事故表中存在空白。例如; 1 月 1 日 0100 时、0200 时和 0300 时,没有紧急电话打进来。因此,我无法使用火灾事故表进行计算,因为没有没有电话打入时的数据。有间隙的火灾事故表如下所示:

时间间隔、事件地址

2017 年 1 月 1 日 00:00:00, 榆树街 123 号

2017 年 1 月 1 日 04:00:00,橡树街 456 号

2017 年 1 月 1 日 05:00:00,枫树街 789 号

(请注意,0100、0200 和 0300 没有火警电话。这些是时间间隔。) 因为数据中存在间隙,其中零应该是泊松分布所需的计算平均值缺失。平均值不正确。

所需输出: 我的目标是拥有一个包含一天中的小时表的日历,以加入我的火灾事件,以便我的结果集返回。这是一个查询的草稿,如果存在匹配值,则返回日历表中的每一行和火灾事件表中的行。

SELECT
  TimeInterval
, COUNT(Incidents) AS [CountOfIncidents] /*this should probably be a     COALESCE statement*/
FROM CalendarTable /*all rows from the calendar with hours and rows with data from FireIncidents*/
LEFT OUTER JOIN FireIncidents ON CalendarTable.timeInterval = FireIncidents.TimeInterval
GROUP BY TimeInterval 

查询将返回我希望实现的目标:

时间间隔,事件计数

2017 年 1 月 1 日 00:00:00, 5

2017 年 1 月 1 日 01:00:00, 0

2017 年 1 月 1 日 02:00:00, 0

2017 年 1 月 1 日 03:00:00, 0

2017 年 1 月 1 日 04:00:00, 2

2017 年 1 月 1 日 05:00:00, 1

(请注意,0100、0200 和 0300 的时间有零次呼叫。这就是我想要的!现在我可以创建一个直方图,显示有多少小时有零次呼叫。或者我可以计算考虑到零次呼叫的平均值一天中的部分时间。)

我尝试过的: 我已经尝试了以下方法,但我无法弄清楚如何从中创建表格以及如何使其成为成品,正如您在下面的问题段落中看到的那样。

DECLARE @DayOfYearNumber INT
DECLARE @HourNumber INT

SET @DayOfYearNumber = 1
SET @HourNumber = 0
PRINT 'Year' + ', ' + 'CalendarDayOfYear' + ', ' + 'HourOfDay'
WHILE @DayOfYearNumber < 366
BEGIN
SET @HourNumber = 0
WHILE @HourNumber < 24
BEGIN PRINT '2017' + ', ' + CONVERT(VARCHAR, @DayOfYearNumber) + '  ' +     CONVERT(VARCHAR, @HourNumber)
SET @HourNumber = @HourNumber + 1
END
SET @DayOfYearNumber = @DayOfYearNumber + 1
END

问题:

如何在 SQL Server 2012 中生成包含一年中的每一天和每天的每个小时的日历表。又是我的例子

2017 年 1 月 1 日 00:00:00

2017 年 1 月 1 日 01:00:00

2017 年 1 月 1 日 02:00:00

2017 年 1 月 1 日 03:00:00

2017 年 1 月 1 日 04:00:00

2017 年 1 月 1 日 05:00:00

2017 年 1 月 1 日 06:00:00

2017 年 1 月 1 日 07:00:00

2017 年 1 月 1 日 08:00:00

等等直到年底

2017年12月31日21:00:00

2017年12月31日22:00:00

2017年12月31日23:00:00

年底

sql sql-server calendar
4个回答
4
投票

一个简单的方法使用递归:

with d as (
      select cast('2017-01-01' as datetime) as dte
      union all
      select dateadd(hour, 1, dte)
      from d
      where dateadd(hour, 1, dte) < '2018-01-01'
     )
select d.*
from d
option (maxrecursion 0);

虽然递归速度惊人地快,但如果您需要多次使用它,您可能需要考虑使用数字表或将其存储在临时表或永久表中。


2
投票

使用 rCTE 的另一种方法是计数表,因为它不是 RBAR:

DECLARE @TopDate date = '20550101';

WITH N AS(
    SELECT *
    FROM (VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) V(N)),
Tally AS(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS I
    FROM N N1
         CROSS JOIN N N2
         CROSS JOIN N N3
         CROSS JOIN N N4
         CROSS JOIN N N5
         CROSS JOIN N N6)
SELECT DATEADD(HOUR, I, '20170101') AS DateValue
FROM Tally
WHERE DATEADD(HOUR, I, '20170101') < @TopDate;

1
投票

您可以使用单个查询来实现它。您所需要的只是计数(数字)表:

WITH tally(n) AS (
  SELECT ROW_NUMBER() OVER(ORDER BY 1/0)-1
  FROM master..spt_values s1, master..spt_values s2, master..spt_values s3
)
-- INSERT INTO calendar(col_name)
SELECT DATEADD(HOUR,n,'20170101') AS d
FROM tally
WHERE DATEADD(HOUR,n,'20170101') <= '20180101'

Rextester 演示


0
投票

在 SQL Server 2022 中,您可以使用 GENERATE_SERIES 来执行此操作。请参阅https://www.sqlservercentral.com/articles/using-of-generate_series

--Generate a calendar table with 1 record per hour
SELECT DateDiff(hour,'2017-01-01','2018-01-01') as HoursTillEndOfYear;
  
SELECT DATEADD(HOUR, Hours.value -1 , '2017-01-01') dte
FROM GENERATE_SERIES(1,DateDiff(hour,'2017-01-01','2018-01-01')) Hours

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.