Calendar Table by Interval Minutes
This script will populate one year's worth of date interval records into a calendar table with millisecond precision on the start and end dates.
The calendar table is wide and includes options for querying and displaying date information.
DDL is provided for a Tally table as well as the Calendar table.
/* Script by Marie Bayer (MarieTake3 [at] Yahoo.com)
Populates a table with date brackets in minute intervals
This script uses 15 minutes as the interval but can
easily be modified to use other values.
It creates a full year of dates based on the start
year value passed. Manage data in year sets!
******************* NOTE! NOTE! *******************
This can be used for intervals up to a full day.
Separate scripts for Day/Month and Year are provided
as separate submissions.
***************************************************
The script pulls from the last date in the table
and does ~not~ look for gaps.
I created mine in tempdb so they're available everywhere.
The DDL for the table and a tally table follow the code
section.
*/
USE [tempdb]
GO
/* The variable @StartYear can also be a stored procedure
parameter if desired. I created mine to run without
the option.
@Interval needs to match the value setting @End.
*/
DECLARE
@StartYear INT
,@StartDate DATETIME
,@Interval TINYINT = 15
,@End INT;
/* The next two statements are not necessary if you're passing the
value either as a full @StartDate or @StartYear.
The existing will build on the last value in the
source table.
*/
SET @StartYear = (
SELECT ISNULL(MAX(DATEPART(YY, CalDate)), 2009) + 1
FROM dbo.CalQuarterHour
);
SET @StartDate = CAST(CAST(@StartYear AS CHAR(4)) + '-01-01' AS DATETIME);
/* Set this to match your @interval! Neglecting it will make for incomplete
results and/or very odd results.
15 minute intervals = 96 records
30 minute intervals = 48 records
60 minute intervals = 24 records (can also use the Day script)
*/
SET @End = DATEPART(DY, DATEADD(DD, -1, DATEADD(YY, 1, @StartDate))) * 96;
/* DDL for this table follows. All my calendar tables have the exact same
format for portability when the code needs to change from one interval
to another.
*/
INSERT INTO dbo.CalQuarterHour
(
CalStartDt
,CalEndDt
,CalDayOfWeekNumber
,CalDayNumber
,CalMonthNumber
,CalYearNumber
,CalDayName
,CalMonthName
,CalDayText
,CalMonthText
,CalYearText
,CalYearMonthText
,CalMonthYearText
,CalDate
)
SELECT
DATEADD(MI, (N - 1) * @Interval, @StartDate) AS CalStartDt
,DATEADD(MS, -1 ,CAST(DATEADD(MI, N * @Interval, @StartDate) AS DATETIME2(3))) AS CalEndDt -- Odd issue with DATETIME not taking off the microsecond. Try it and see.
,DATEPART(DW, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CalDayOfWeekNumber
,DATEPART(DD, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CalDayNumber
,DATEPART(MM, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CalMonthNumber
,DATEPART(YY, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CalYearNumber
,DATENAME(DW, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CalDayName
,DATENAME(MM, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CalMonthName
,CASE WHEN
LEN(DATEPART(DD, DATEADD(MI, (N - 1) * @Interval, @StartDate))) = 1 THEN '0' + CAST(DATEPART(DD, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CHAR(1))
ELSE CAST(DATEPART(DD, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CHAR(2))
END AS CalDayText
,CASE WHEN
LEN(DATEPART(MM, DATEADD(MI, (N - 1) * @Interval, @StartDate))) = 1 THEN '0' + CAST(DATEPART(MM, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CHAR(1))
ELSE CAST(DATEPART(MM, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CHAR(2))
END AS CalMonthText
,CAST(DATEPART(YY, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CHAR(4)) AS CalYearText
,CAST(DATEPART(YY, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CHAR(4)) + '-' +
CASE WHEN
LEN(DATEPART(MM, DATEADD(MI, (N - 1) * @Interval, @StartDate))) = 1 THEN '0' + CAST(DATEPART(MM, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CHAR(1))
ELSE CAST(DATEPART(MI, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CHAR(2))
END AS CalYearMonthText
,DATENAME(MM, DATEADD(MI, (N - 1) * @Interval, @StartDate)) + CHAR(32) + DATENAME(YY, DATEADD(MI, (N - 1) * @Interval, @StartDate)) AS CalMonthYearText
,CAST(CAST(DATEADD(MI, (N - 1) * @Interval, @StartDate) AS DATE) AS CHAR(10)) AS CalDate
FROM dbo.Tally AS T
WHERE N < @End + 1;
/* Table DDL
*/
/* Tally Table
USE [tempdb]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Tally]') AND type in (N'U'))
DROP TABLE [dbo].[Tally]
GO
CREATE TABLE dbo.Tally (N INT, CONSTRAINT PK_Tally_N PRIMARY KEY CLUSTERED (N));
DECLARE
@Counter INT = 1;
WHILE @Counter <= 100000
BEGIN
INSERT INTO dbo.Tally (
N
)
VALUES (
@Counter
);
SET @Counter = @Counter + 1;
END;
*/
/* Calendar Table
USE [tempdb]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[CalQuarterHour]') AND type in (N'U'))
DROP TABLE [dbo].[CalQuarterHour]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[CalQuarterHour](
[CalID] [int] IDENTITY(1,1) NOT NULL,
[CalStartDt] [datetime2](3) NULL,
[CalEndDt] [datetime2](3) NULL,
[CalDayOfWeekNumber] [int] NULL,
[CalDayNumber] [int] NULL,
[CalMonthNumber] [int] NULL,
[CalYearNumber] [int] NULL,
[CalDayName] [varchar](10) NULL,
[CalMonthName] [varchar](10) NULL,
[CalDayText] [char](2) NULL,
[CalMonthText] [char](2) NULL,
[CalYearText] [char](4) NULL,
[CalYearMonthText] [char](7) NULL,
[CalMonthYearText] [varchar](15) NULL,
[CalDate] [date] NULL,
CONSTRAINT [PK_CalQuarterHour] PRIMARY KEY CLUSTERED
(
[CalID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
*/