Постановка проблемы: Я работаю в пожарной части и занимаюсь статистическим анализом моих данных. Одна проблема состоит в том, чтобы генерировать количество вызовов на обслуживание для каждого часа каждого дня в течение календарного года. Мне нужен стол, который можно присоединить к инцидентам с пожарами, которые происходят каждый день года и каждый час каждого дня. Я надеюсь на следующее (используя военное время)
1 января 2017 00:00:00
1 января 2017 00:00:00
1 января 2017 года 01:00:00
1 января 2017 02:00:00
1 января 2017 03:00:00
1 января 2017 04:00:00
1 января 2017 года 05:00:00
1 января 2017 г. 06:00:00
1 января 2017 года 07:00:00
1 января 2017 года 08:00:00
И т.д. до конца года
31 декабря 2017 года 21:00:00
31 декабря 2017 года 22:00:00
31 декабря 2017 года 23:00:00
Конец года
Эта таблица позволит мне присоединиться к таблице пожарных происшествий, и я смогу статистически рассчитать количество инцидентов для каждого часа дня и для каждого дня года. Расчетная таблица необходима, потому что в таблице пожарных происшествий есть пробелы. Например; 1 января в 01:00, 02:00 и 03:00 не поступали экстренные вызовы. Поэтому я не могу сделать расчет с использованием таблицы пожарных происшествий, потому что нет данных о том, когда не поступали звонки. Таблица пожарных происшествий с пробелами выглядит следующим образом:
Интервал времени, адрес инцидента
1 января 2017 00:00:00, улица Вязов 123
1 января 2017 04:00:00, улица Дуба 456
1 января 2017 05:00:00, 789 Maple Street
(Обратите внимание, что в часы 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
Запрос вернет то, что я надеюсь достичь:
Интервал времени, Количество Инцидентов
1 января 2017 00:00:00, 5
1 января 2017 года 01:00:00, 0
1 января 2017 02:00:00, 0
1 января 2017 03:00:00, 0
1 января 2017 04:00:00, 2
1 января 2017 года 05:00:00, 1
(Обратите внимание, что часы 0100, 0200 и 0300 имеют нулевое количество вызовов. Это то, что я хочу! Теперь я могу создать гистограмму, показывающую, сколько часов было 0 вызовов. Или я могу рассчитать среднее значение, которое учитывает нулевые вызовы для части дня.)
Что я пробовал: Я попробовал следующее, но не могу понять, как создать из этого таблицу и как сделать ее готовым продуктом, как вы можете видеть ниже в пункте «Вопрос».
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, которая будет иметь каждый день года и каждый час каждого дня. Мой пример снова
1 января 2017 00:00:00
1 января 2017 года 01:00:00
1 января 2017 02:00:00
1 января 2017 03:00:00
1 января 2017 04:00:00
1 января 2017 года 05:00:00
1 января 2017 г. 06:00:00
1 января 2017 года 07:00:00
1 января 2017 года 08:00:00
И т.д. до конца года
31 декабря 2017 года 21:00:00
31 декабря 2017 года 22:00:00
31 декабря 2017 года 23:00:00
Конец года
3 ответа
Простой метод использует рекурсию:
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);
Хотя рекурсия на удивление быстрая, если вам понадобится это несколько раз, вы можете рассмотреть вопрос о наличии таблицы чисел или ее сохранении во временной или постоянной таблице.
Вы можете достичь этого с помощью одного запроса. Все, что вам нужно, это таблица подсчета (номер):
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'
Альтернативным методом использования 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;
Связанные вопросы
Новые вопросы
sql
Язык структурированных запросов (SQL) - это язык запросов к базам данных. Вопросы должны включать примеры кода, структуру таблицы, примеры данных и тег для используемой реализации СУБД (например, MySQL, PostgreSQL, Oracle, MS SQL Server, IBM DB2 и т. Д.). Если ваш вопрос относится исключительно к конкретной СУБД (использует определенные расширения / функции), используйте вместо этого тег этой СУБД. Ответы на вопросы, помеченные SQL, должны использовать стандарт ISO / IEC SQL.