Periodically, you'll need to add to the date dimension. Over the years, I've worked out a fairly simple, but sound date dimension create and update process. Below are the details:
DateKey
Dates never change, so the datekey can have intelligence. It is one of the few dimensions that can break the rule where a dimension key should never have intelligence. The datakey uses the ISO format: YYYYMMDD. This allows you to assign a datekey to business data using only the date, without having to reference the date dimension.
The scripts
create schema rds; go IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[rds].[Date_dim]') AND type in (N'U')) DROP TABLE [rds].[Date_dim] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [rds].[Date_dim]( [DateKey] [int] NOT NULL, [FullDateAltKey] [date] NULL, [DayOfWeekNum] [tinyint] NULL, [DayOfWeekName] [nvarchar](10) NULL, [DayOfMonthNum] [tinyint] NULL, [DayOfYearNum] [smallint] NULL, [WeekOfYearNum] [tinyint] NULL, [MonthOfYearName] [nvarchar](10) NULL, [MonthOfYearNum] [tinyint] NULL, [CalendarQuarter] [tinyint] NULL, [CalendarYear] [smallint] NULL, [CalendarSemester] [tinyint] NULL, [FiscalPeriod] [tinyint] NULL, [FiscalQuarter] [tinyint] NULL, [FiscalYear] [smallint] NULL, [FiscalSemester] [tinyint] NULL, [FiscalDayOfPeriodNum] [tinyint] NULL, [FiscalDayOfYearNum] [smallint] NULL, [FiscalWeekOfYearNum] [tinyint] NULL, [FiscalPeriodOfYearName] [nvarchar](10) NULL, [SimpleCalendarDate] [varchar](20) NULL, [SimpleFiscalDate] [varchar](20) NULL, [SimpleCalendarMonth] [varchar](20) NULL, [SimpleCalendarQtr] [char](5) NULL, [SimpleFiscalQtr] [char](5) NULL, [SimpleFiscalYear] [char](7) NULL, [SimpleCalendarYear] [char](7) NULL, [CalendarQuarterDesc] [char](10) NULL, [FiscalQuarterDesc] [char](10) NULL, [CalendarSemesterDesc] [char](10) NULL, [FiscalSemesterDesc] [char](10) NULL, [SimpleFiscalPeriod] [varchar](20) NULL, [SimpleFiscalPeriodNo] [int] NULL, [FiscalPeriodLabel] [nchar](2) NULL, ) ON [PRIMARY] GO SET ANSI_PADDING OFF GO IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[rds].[Date_dim]') AND name = N'PK_rds_Date_dim_DateKey') DROP INDEX [PK_rds_Date_dim_DateKey] ON [rds].[Date_dim] WITH ( ONLINE = OFF ) GO CREATE UNIQUE CLUSTERED INDEX [PK_rds_Date_dim_DateKey] ON [rds].[Date_dim] ( [DateKey] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO
The following section, adds the core date data, Typically, this is added one year at a time.
But, it can be extended to insert as many years as needed.
/* -----------------------------------------------------
-----------------------------------------------------
Process to add records to the rds.Date_dim
In production, dates are added one year at a time.
Alternatively, you could front load the table with
20-30 years into future.
@intLOOPend= 370 -- added as simple infinite loop break,
@dtStartDate = 'jan 1, 2014' -- calendar year start
@dtEndDate = 'december 31, 2014'; -- calendar year end
Fiscal dates vary, so they are not included
----------------------------------------------------- */
set nocount on;
SET DATEFIRST 7; -- 7=default=sunday, monday=1
go
declare @intLOOPcnt int, @intLOOPend int , @dtStartDate datetime, @dtEndDate datetime, @dtProcessDate datetime;
-- KEY SETTINGS / INPUTS
Select @intLOOPcnt = 0,@intLOOPend= 4000
, @dtStartDate = 'Jan 1, 2000', @dtEndDate = 'December 31, 2004';
-- init date to be processed
select @dtProcessDate = @dtStartDate;
while @intLOOPcnt < @intLOOPend AND @dtProcessDate <= @dtEndDate
begin
/*debug*/ --print 'test' + cast(@dtProcessDate as varchar)
BEGIN TRY
-- insert
insert into rds.Date_dim
( dateKey, fullDateAltKey, dayOfWeekNum, DayOfWeekName, dayOfMonthNum, dayOfYearNum
, weekOfYearNum
, MonthOfYearName, monthOfYearNum
, calendarQuarter, calendarYear, calendarSemester
--, fiscalYear, FiscalDayOfYearNum,FiscalPeriodLabel
--, fiscalQuarter, fiscalSemester
)
select
dateKey = cast(CONVERT( varchar(8), @dtProcessDate , 112) as int)
, fullDateAltKey = CONVERT( varchar(8), @dtProcessDate , 112)
, dayOfWeekNum = datepart(weekday,@dtProcessDate)
, DayOfWeekName = datename(weekday,@dtProcessDate)
, dayOfMonthNum = datepart(day,@dtProcessDate)
, dayOfYearNum = datepart(dayofyear,@dtProcessDate)
, weekOfYearNum = datepart(week,@dtProcessDate)
, MonthOfYearName = datename(month,@dtProcessDate)
, monthOfYearNum = datepart(month,@dtProcessDate)
, calendarQuarter = datepart(quarter,@dtProcessDate)
, calendarYear = datepart(year,@dtProcessDate)
, calendarSemester = case when datepart(quarter,@dtProcessDate) in (1,2) then 1 else 2 end
--, fiscalYear = datepart(year,@dtProcessDate)
--, FiscalDayOfYearNum = datepart(dayofyear,@dtProcessDate)
--, FiscalPeriodLabel = ' '
;
END TRY
BEGIN CATCH
print 'CATCH - error: ' + cast(@@error as varchar) + ', ProcessDate: '+ cast(@dtProcessDate as varchar);
END CATCH
-- next item
select @intLOOPcnt = @intLOOPcnt + 1;
select @dtProcessDate = dateadd(day,1,@dtProcessDate );
end
go
This final section simply updates the few remaining values. To keep the build script simple, I separated this out of the main insert. You could include it, but this is run infrequently, and simplicity is more important than having an impressive, but complex insert statement.
------------------------------------------------------------------------------------------------------------------------- -- OTHER CALENDAR VALUES FOR UPDATE ------------------------------------------------------------------------------------------------------------------------- update d set -- select top 50 SimpleCalendarDate = MonthOfYearName + ' ' + CAST(DayOfMonthNum as varchar) + ', ' + cast(CalendarYear as varchar) ,SimpleCalendarMonth = MonthOfYearName + ' ' + cast(CalendarYear as varchar) ,SimpleCalendarQtr = 'CY Q' + CAST(CalendarQuarter as CHAR(1)) ,SimpleCalendarYear = 'CY ' + cast(CalendarYear as varchar) ,CalendarQuarterDesc = 'Q' + CAST(CalendarQuarter as CHAR(1)) + ' CY ' + cast(CalendarYear as varchar) ,CalendarSemesterDesc = 'H' + cast(CalendarSemester as CHAR(1)) + ' CY ' + cast(CalendarYear as varchar) from rds.date_dim as d WHERE d.DateKey between 20050101 and 20051231;
No comments:
Post a Comment