Мне нравится такой подход к построению таблицы месяцев:
SELECT
DATENAME(mm, date_val) AS month_name,
MONTH(date_val) AS month_number,
date_val as dt
FROM (
SELECT DATEADD(mm, number, '2010-01-01') AS date_val
FROM master.dbo.spt_values
WHERE type = 'P'
AND number BETWEEN 0 AND 11
) months
На основании моих тестов он работает быстрее, чем CTE.Я использую SQL Server 2008 Express.
Вот результаты теста с использованием SET STATISTICS IO ON и SET STATISTICS TIME ON
CTE:
(12 row(s) affected)
Table 'Worktable'. Scan count 2, logical reads 73, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 15 ms, elapsed time = 64 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
Подзапрос:
(12 row(s) affected)
Table 'spt_values'. Scan count 1, logical reads 2, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 4 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
Хотя ваш оригинальный вопрос спрашивает, как это называется.Я не знаю имени для этого;может быть что-то вроде «левого внешнего соединения с серией»?
Еще одна дополнительная деталь, которую нужно добавить: когда вы соединяетесь с таблицей месяцев или даже когда делаете исходный запрос, обычно рекомендуется избегать использования такой функции, как YEAR([отметка времени]) в левой части предложения WHERE.
Таким образом, этот код:
SELECT
YEAR([timestamp]),
MONTH([timestamp]),
COUNT(*)
FROM table1
WHERE YEAR([timestamp]) = YEAR(GETDATE())
GROUP BY
YEAR([timestamp]),
MONTH([timestamp])
... вызовет сканирование индекса (при условии, что временная метка проиндексирована), поскольку ГОД ([временная метка]) должен оцениваться для каждой строки.В таблице строк размером более 1 м это будет означать низкую производительность.
Таким образом, вместо этого вы обычно увидите следующую рекомендацию:
SELECT
YEAR([timestamp]),
MONTH([timestamp]),
COUNT(*)
FROM #table1
WHERE [timestamp] >= DATEADD(YY, DATEDIFF(YY, 0, GETDATE()), 0) -- First day of this year
AND [timestamp] < DATEADD(YY, DATEDIFF(YY, 0, GETDATE()) + 1, 0) -- First day of next year
GROUP BY
YEAR([timestamp]),
MONTH([timestamp])
При этом будет использоваться поиск по индексу (опять-таки, предполагая, что метка временииндексированный столбец), что приводит к меньшему количеству логических чтений и, следовательно, к более быстрому ответу.Это можно подтвердить, проверив план выполнения.