Измерение даты и времени -- ключевая и обязательная сущность любого хранилища данных или аналитической системы. В данной статье будет приведен пример создания типовой таблицы календаря с гранулярностью до уровня дня. Для создания данной таблицы нам понадобится таблица dbo.Numbers из предыдущей статьи. Полный код и результаты работы можно посмотреть здесь.
Создадим таблицу dbo.DimDate. В качестве кластерного ключа таблицы будем использовать суррогатный целочисленный ключ, представленный в формате YYYYMMDD. Ниже представлен скрипт создания таблицы календаря, а также скрипт создания дополнительной таблицы dbo.Numbers.
Создадим таблицу dbo.DimDate. В качестве кластерного ключа таблицы будем использовать суррогатный целочисленный ключ, представленный в формате YYYYMMDD. Ниже представлен скрипт создания таблицы календаря, а также скрипт создания дополнительной таблицы dbo.Numbers.
if object_id('dbo.DimDate', 'U') is not null drop table dbo.DimDate go create table [dbo].[DimDate]( [DateKey] [int] NOT NULL, [DateValue] [date] NOT NULL, [DateName] [nvarchar](10) NOT NULL, [Year] [int] NOT NULL, [Quarter] [tinyint] NOT NULL, [QuarterName] [nchar](15) NOT NULL, [MonthNum] [tinyint] NOT NULL, [MonthName] [nvarchar](15) NOT NULL, [DayOfWeek] [tinyint] NOT NULL, [DayOfMonth] [tinyint] NOT NULL, [DayOfYeear] [smallint] NOT NULL, [DayName] [nvarchar](15) NOT NULL, [DayNameShort] [nchar](2) NOT NULL, [WeekOfYear] [tinyint] NOT NULL, [WeekOfMonth] [tinyint] NOT NULL, [WeekName] [nchar](23) NOT NULL, [IsWeekend] [tinyint] NOT NULL, [IsPreWeekend] [tinyint] NOT NULL ) go alter table [dbo].[DimDate] add constraint [PK_DimDate] primary key([DateKey]) alter table [dbo].[DimDate] add constraint [DF_DimDate_Weekend] default ((0)) for [IsWeekend] alter table [dbo].[DimDate] add constraint [DF_DimDate_PreWeekend] default ((0)) for [IsPreWeekend] go if object_id('dbo.Numbers', 'U') is not null drop table dbo.Numbers go select top(1000000) n = row_number() over(order by s1.number) into dbo.Numbers from master..spt_values s1, master..spt_values s2 option (maxdop 1); go create unique clustered index ix_numbers_n on dbo.Numbers(n)Ниже представлен алгоритм заполнения таблицы календаря. Результаты выполнения запроса можно посмотреть здесь
/* Установка параметров сессии, влияющих на выполнение запроса */ set language russian set dateformat 'ymd' set datefirst 1 /* Определяем первый день года и последний */ declare @s date = '2014-01-01'; declare @e date = dateadd(day, -1, dateadd(year, 2, @s)); /* Выходные по производственному календарю 2015 и 2014 годов */ ;with Holiday(DateKey) as ( select 20150101 union all select 20150102 union all select 20150105 union all select 20150106 union all select 20150107 union all select 20150108 union all select 20150109 union all select 20150223 union all select 20150309 union all select 20150501 union all select 20150504 union all select 20150511 union all select 20150612 union all select 20151104 union all select 20140101 union all select 20140102 union all select 20140103 union all select 20140106 union all select 20140107 union all select 20140108 union all select 20140310 union all select 20140501 union all select 20140502 union all select 20140509 union all select 20140612 union all select 20140613 union all select 20141103 union all select 20141104 ), /* Сокращенные дни по производственному календарю на 2014 и 2015 года */ PreHoliday(DateKey) as ( select 20150430 union all select 20150508 union all select 20150611 union all select 20151103 union all select 20151231 union all select 20141231 union all select 20140307 union all select 20140430 union all select 20140611 union all select 20140805 ) insert into dbo.DimDate select DateKey = d.DateKey, -- 20140101 DateValue = DateValue, DateName = Convert(nvarchar(10), DateValue, 104), -- 01.01.2014 Year = Year(DateValue), Quarter = Datepart(QUARTER, DateValue), QuarterName = N'Квартал ' + Convert(nvarchar(1), Datepart(QUARTER, DateValue)) + ', ' + Convert(nvarchar(4),Year(DateValue)), -- Квартал 1, 2014 MonthNum = Month(DateValue), MonthName = Datename(MONTH, DateValue)+ ', ' + Convert(nvarchar(4),Year(DateValue)), -- Январь, 2014 DayOfWeek = DatePart(DW, DateValue), DayOfMonth = Day(DateValue), DayOfYear = DatePart(DY, DateValue), DayName = Upper(Left(DateName(DW, DateValue),1)) + Substring(DateName(DW, DateValue), 2, Len(DateName(DW, DateValue)) ), DayNameShort = Case When DateName(DW, DateValue) = N'понедельник' Then N'Пн' When DateName(DW, DateValue) = N'вторник' Then N'Вт' When DateName(DW, DateValue) = N'среда' Then N'Ср' When DateName(DW, DateValue) = N'четверг' Then N'Чт' When DateName(DW, DateValue) = N'пятница' Then N'Пт' When DateName(DW, DateValue) = N'суббота' Then N'Сб' When DateName(DW, DateValue) = N'воскресенье' Then N'Вс' End, WeekOfYear = DatePart(WK, DateValue), WeekOfMonth = dense_rank() over(partition by Year(DateValue), Month(DateValue) order by DatePart(WK, DateValue)), WeekName = Convert(nvarchar(10), Min(DateValue) over(partition by Year(DateValue), Datepart(WK, DateValue)), 104) + ' - ' + Convert(nvarchar(10), Max(DateValue) over(partition by Year(DateValue), Datepart(WK, DateValue)), 104), -- 01.01.2014 - 05.01.2014 IsWeekend = Case When Holiday.DateKey is not null or DatePart(DW, DateValue) in (6,7) Then 1 Else 0 End, IsPreWeekend = Case When PreHoliday.DateKey is not null Then 1 Else 0 End from ( select top (datediff(day, @s, @e) + 1) DateKey = Convert(int, Convert(nvarchar(8), Convert(date, DateAdd(Day, n-1, @s)), 112)), -- Ключ даты формата YYYYMMDD DateValue = Convert(date, DateAdd(day, n-1, @s)) from dbo.Numbers order by n ) d left join Holiday on Holiday.DateKey = d.DateKey left join PreHoliday on PreHoliday.DateKey = d.DateKey