如何创建日期表

Mig*_*uel 2 sql-server

我在尝试创建 DimDate 时遇到问题。

这就是我尝试过的:

CREATE TABLE [dbo].[DimDate] (
    /*[ID] [int] IDENTITY(1,1) NOT NULL--Use this line if you just want an  autoincrementing counter AND COMMENT BELOW LINE*/
    [ID] [VARCHAR](10) NOT NULL --TO MAKE THE ID THE YYYYMMDD FORMAT USE THIS LINE AND COMMENT ABOVE LINE.
    ,[Date] [DATETIME] NOT NULL
    ,[StandardDate] [VARCHAR](10) NULL
    ,[Day] [CHAR](2) NOT NULL
    ,[DaySuffix] [VARCHAR](4) NOT NULL
    ,[DayOfWeek] [VARCHAR](9) NOT NULL
    ,[DOWInMonth] [TINYINT] NOT NULL
    ,[DayOfYear] [INT] NOT NULL
    ,[WeekOfMonth] [TINYINT] NOT NULL
    ,[WeekOfYear] [TINYINT] NOT NULL
    ,[Month] [CHAR](2) NOT NULL
    ,[MonthName] [VARCHAR](9) NOT NULL
    ,[Quarter] [VARCHAR] NOT NULL
    ,[QuarterName] [VARCHAR](6) NOT NULL
    ,[Year] [CHAR](4) NOT NULL
    ,[MonthYear] [VARCHAR](10) NULL
    ,[MMYYY] [VARCHAR](6) NULL
    ,[FirstDayOfMonth] [DATE] NULL
    ,[LastDayOfMonth] [DATE] NULL
    ,[FirstDayOfQuarter] [DATE] NULL
    ,[LastDayOfQuarter] [DATE] NULL
    ,[FirstDayOfYear] [DATE] NULL
    ,[LastDayOfYear] [DATE] NULL
    ,[HolidayText] [VARCHAR](50) NULL CONSTRAINT [PKDimDate] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (
        PAD_INDEX = OFF
        ,STATISTICS_NORECOMPUTE = OFF
        ,IGNORE_DUP_KEY = OFF
        ,ALLOW_ROW_LOCKS = ON
        ,ALLOW_PAGE_LOCKS = ON
        ,FILLFACTOR = 90
        ) ON [PRIMARY]
    ) ON [PRIMARY]

/*******************************************************************************************************************************************************/
TRUNCATE TABLE [dbo].[DimDate]

/*IF YOU ARE USING THE YYYYMMDD format for the primary key then you need to comment out this line.
DBCC CHECKIDENT ([dbo].[DimDate], RESEED, 60000) --In case you need to add earlier dates later.*/
/*Table for counting DOW occurance in a month*/
DECLARE @tmpDOW TABLE (
    DOW INT
    ,Cntr INT
    )

INSERT INTO @tmpDOW (
    DOW
    ,Cntr
    )
VALUES (
    1
    ,0
    )

INSERT INTO @tmpDOW (
    DOW
    ,Cntr
    )
VALUES (
    2
    ,0
    )

INSERT INTO @tmpDOW (
    DOW
    ,Cntr
    )
VALUES (
    3
    ,0
    )

INSERT INTO @tmpDOW (
    DOW
    ,Cntr
    )
VALUES (
    4
    ,0
    )

INSERT INTO @tmpDOW (
    DOW
    ,Cntr
    )
VALUES (
    5
    ,0
    )

INSERT INTO @tmpDOW (
    DOW
    ,Cntr
    )
VALUES (
    6
    ,0
    )

INSERT INTO @tmpDOW (
    DOW
    ,Cntr
    )
VALUES (
    7
    ,0
    )

DECLARE @StartDate DATETIME
    ,@EndDate DATETIME
    ,@Date DATETIME
    ,@WDofMonth INT
    ,@CurrentMonth INT

SELECT @StartDate = '1/1/1995'
    /*Non inclusive. Stops on the day before this.*/
    ,@EndDate = '1/1/2025'
    ,@CurrentMonth = 1

SELECT @Date = @StartDate

/*******************************************************************************************************************************************************/
WHILE @Date < @EndDate
BEGIN
    IF DATEPART(MONTH, @Date) <> @CurrentMonth
    BEGIN
        SELECT @CurrentMonth = DATEPART(MONTH, @Date)

        UPDATE @tmpDOW
        SET Cntr = 0
    END

    UPDATE @tmpDOW
    SET Cntr = Cntr + 1
    WHERE DOW = DATEPART(DW, @DATE)

    SELECT @WDofMonth = Cntr
    FROM @tmpDOW
    WHERE DOW = DATEPART(DW, @DATE)

    INSERT INTO [dbo].[DimDate] (
        [ID]
        ,/*TO MAKE THE ID THE YYYYMMDD FORMAT UNCOMMENT THIS LINE... Comment for autoincrementing.*/
        [Date]
        ,[StandardDate]
        ,[Day]
        ,[DaySuffix]
        ,[DayOfWeek]
        ,[DOWInMonth]
        ,[DayOfYear]
        ,[WeekOfMonth]
        ,[WeekOfYear]
        ,[Month]
        ,[MonthName]
        ,[Quarter]
        ,[QuarterName]
        ,[Year]
        )
    SELECT CONVERT(VARCHAR, @Date, 112) AS [ID]
        ,/*TO MAKE THE ID THE YYYYMMDD FORMAT UNCOMMENT THIS LINE COMMENT FOR AUTOINCREMENT*/
        @Date AS [Date]
        ,RIGHT('0' + CONVERT(VARCHAR, DATEPART(MONTH, @DATE)), 2) + '/' + RIGHT('0' + CONVERT(VARCHAR, DATEPART(DAY, @DATE)), 2) + '/' + CONVERT(VARCHAR, DATEPART(YEAR, @Date)) AS [StandardDate]
        ,RIGHT('0' + CONVERT(VARCHAR, DATEPART(DAY, @DATE)), 2) AS [Day]
        ,CASE 
            WHEN DATEPART(DAY, @DATE) IN (
                    11
                    ,12
                    ,13
                    )
                THEN CAST(DATEPART(DAY, @DATE) AS VARCHAR) + 'th'
            WHEN RIGHT(DATEPART(DAY, @DATE), 1) = 1
                THEN CAST(DATEPART(DAY, @DATE) AS VARCHAR) + 'st'
            WHEN RIGHT(DATEPART(DAY, @DATE), 1) = 2
                THEN CAST(DATEPART(DAY, @DATE) AS VARCHAR) + 'nd'
            WHEN RIGHT(DATEPART(DAY, @DATE), 1) = 3
                THEN CAST(DATEPART(DAY, @DATE) AS VARCHAR) + 'rd'
            ELSE CAST(DATEPART(DAY, @DATE) AS VARCHAR) + 'th'
            END AS [DaySuffix]
        ,CASE DATEPART(DW, @DATE)
            WHEN 1
                THEN 'Sunday'
            WHEN 2
                THEN 'Monday'
            WHEN 3
                THEN 'Tuesday'
            WHEN 4
                THEN 'Wednesday'
            WHEN 5
                THEN 'Thursday'
            WHEN 6
                THEN 'Friday'
            WHEN 7
                THEN 'Saturday'
            END AS [DayOfWeek]
        ,@WDofMonth AS [DOWInMonth] /*Occurance of this day in this month. If Third Monday then 3 and DOW would be Monday.*/
        ,DATEPART(dy, @Date) AS [DayOfYear] /*Day of the year. 0 - 365/366*/
        ,DATEPART(ww, @Date) + 1 - DATEPART(ww, CAST(DATEPART(mm, @Date) AS VARCHAR) + '/1/' + CAST(DATEPART(yy, @Date) AS VARCHAR)) AS [WeekOfMonth]
        ,DATEPART(ww, @Date) AS [WeekOfYear] /*0-52/53*/
        ,RIGHT('0' + CONVERT(VARCHAR, DATEPART(MONTH, @DATE)), 2) AS [Month]
        ,DATENAME(MONTH, @DATE) AS [MonthName]
        ,DATEPART(qq, @DATE) AS [Quarter] /*Calendar quarter*/
        ,CASE DATEPART(qq, @DATE)
            WHEN 1
                THEN 'First'
            WHEN 2
                THEN 'Second'
            WHEN 3
                THEN 'Third'
            WHEN 4
                THEN 'Fourth'
            END AS [QuarterName]
        ,DATEPART(YEAR, @Date) AS [Year]

    SELECT @Date = DATEADD(dd, 1, @Date)
END

/*******************************************************************************************************************************************************/
/*Set first and last days of the months*/
UPDATE [dbo].[DimDate]
SET FirstDayOfMonth = minmax.StartDate
    ,LastDayOfMonth = minmax.EndDate
FROM [dbo].[DimDate] t
    ,(
        SELECT [Month]
            ,[Quarter]
            ,[Year]
            ,MIN([Date]) AS StartDate
            ,MAX([Date]) AS EndDate
        FROM [dbo].[DimDate]
        GROUP BY [Month]
            ,[Quarter]
            ,[Year]
        ) minmax
WHERE t.[Month] = minmax.[Month]
    AND t.[Quarter] = minmax.[Quarter]
    AND t.[Year] = minmax.[Year]

/*Set first and last days of the quarters*/
UPDATE [dbo].[DimDate]
SET FirstDayOfQuarter = minmax.StartDate
    ,LastDayOfQuarter = minmax.EndDate
FROM [dbo].[DimDate] t
    ,(
        SELECT [Quarter]
            ,[Year]
            ,min([Date]) AS StartDate
            ,max([Date]) AS EndDate
        FROM [dbo].[DimDate]
        GROUP BY [Quarter]
            ,[Year]
        ) minmax
WHERE t.[Quarter] = minmax.[Quarter]
    AND t.[Year] = minmax.[Year]

/*Set first and last days of the year*/
UPDATE [dbo].[DimDate]
SET FirstDayOfYear = minmax.StartDate
    ,LastDayOfYear = minmax.EndDate
FROM [dbo].[DimDate] t
    ,(
        SELECT [Year]
            ,min([Date]) AS StartDate
            ,max([Date]) AS EndDate
        FROM [dbo].[DimDate]
        GROUP BY [Year]
        ) minmax
WHERE t.[Year] = minmax.[Year]

/*Set YearMonth*/
UPDATE [dbo].[DimDate]
SET MonthYear = CASE [Month]
        WHEN 1
            THEN 'Jan'
        WHEN 2
            THEN 'Feb'
        WHEN 3
            THEN 'Mar'
        WHEN 4
            THEN 'Apr'
        WHEN 5
            THEN 'May'
        WHEN 6
            THEN 'Jun'
        WHEN 7
            THEN 'Jul'
        WHEN 8
            THEN 'Aug'
        WHEN 9
            THEN 'Sep'
        WHEN 10
            THEN 'Oct'
        WHEN 11
            THEN 'Nov'
        WHEN 12
            THEN 'Dec'
        END + '-' + CONVERT(VARCHAR, [Year])

/*Set MMYYY*/
UPDATE [dbo].[DimDate]
SET MMYYY = RIGHT('0' + CONVERT(VARCHAR, [Month]), 2) + CONVERT(VARCHAR, [Year])

/*******************************************************************************************************************************************************/
/*Add HOLIDAYS*/
/*THANKSGIVING - Fourth THURSDAY in November*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Thanksgiving Day'
WHERE [Month] = 11
    AND [DAYOFWEEK] = 'Thursday'
    AND [DOWInMonth] = 4
GO

/*CHRISTMAS*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Christmas Day'
WHERE [Month] = 12
    AND [Day] = 25
GO

/*4th of July*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Independance Day'
WHERE [Month] = 7
    AND [Day] = 4
GO

/*New Years Day*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'New Year''s Day'
WHERE [Month] = 1
    AND [Day] = 1
GO

/*Memorial Day - Last Monday in May*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Memorial Day'
FROM [dbo].[DimDate]
WHERE ID IN (
        SELECT MAX([ID])
        FROM [dbo].[DimDate]
        WHERE [MonthName] = 'May'
            AND [DayOfWeek] = 'Monday'
        GROUP BY [Year]
            ,[Month]
        )
GO

/*Labor Day - First Monday in September*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Labor Day'
FROM [dbo].[DimDate]
WHERE ID IN (
        SELECT MIN([ID])
        FROM [dbo].[DimDate]
        WHERE [MonthName] = 'September'
            AND [DayOfWeek] = 'Monday'
        GROUP BY [Year]
            ,[Month]
        )
GO

/*Valentine's Day*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Valentine''s Day'
WHERE [Month] = 2
    AND [Day] = 14
GO

/*Saint Patrick's Day*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Saint Patrick''s Day'
WHERE [Month] = 3
    AND [Day] = 17
GO

/*Martin Luthor King Day - Third Monday in January starting in 1983*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Martin Luthor King Jr Day'
WHERE [Month] = 1
    AND [Dayofweek] = 'Monday'
    AND [Year] >= 1983
    AND [DOWInMonth] = 3
GO

/*President's Day - Third Monday in February*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'President''s Day'
WHERE [Month] = 2
    AND [Dayofweek] = 'Monday'
    AND [DOWInMonth] = 3
GO

/*Mother's Day - Second Sunday of May*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Mother''s Day'
WHERE [Month] = 5
    AND [Dayofweek] = 'Sunday'
    AND [DOWInMonth] = 2
GO

/*Father's Day - Third Sunday of June*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Father''s Day'
WHERE [Month] = 6
    AND [Dayofweek] = 'Sunday'
    AND [DOWInMonth] = 3
GO

/*Halloween 10/31*/
UPDATE [dbo].[DimDate]
SET HolidayText = 'Halloween'
WHERE [Month] = 10
    AND [Day] = 31
GO

/*Election Day - The first Tuesday after the first Monday in November*/
BEGIN
    BEGIN TRY
        DROP TABLE #tmpHoliday
    END TRY

    BEGIN CATCH
        /*Do Nothing*/
    END CATCH

    CREATE TABLE #tmpHoliday (
        ID INT IDENTITY(1, 1)
        ,DateID INT
        ,Week TINYINT
        ,YEAR CHAR(4)
        ,DAY CHAR(2)
        )

    INSERT INTO #tmpHoliday (
        DateID
        ,[Year]
        ,[Day]
        )
    SELECT [ID]
        ,[Year]
        ,[Day]
    FROM [dbo].[DimDate]
    WHERE [Month] = 11
        AND [Dayofweek] = 'Monday'
    ORDER BY YEAR
        ,DAY

    DECLARE @CNTR INT
        ,@POS INT
        ,@STARTYEAR INT
        ,@ENDYEAR INT
        ,@CURRENTYEAR INT
        ,@MINDAY INT

    SELECT @CURRENTYEAR = MIN([Year])
        ,@STARTYEAR = MIN([Year])
        ,@ENDYEAR = MAX([Year])
    FROM #tmpHoliday

    WHILE @CURRENTYEAR <= @ENDYEAR
    BEGIN
        SELECT @CNTR = COUNT([Year])
        FROM #tmpHoliday
        WHERE [Year] = @CURRENTYEAR

        SET @POS = 1

        WHILE @POS <= @CNTR
        BEGIN
            SELECT @MINDAY = MIN(DAY)
            FROM #tmpHoliday
            WHERE [Year] = @CURRENTYEAR
                AND [Week] IS NULL

            UPDATE #tmpHoliday
            SET [Week] = @POS
            WHERE [Year] = @CURRENTYEAR
                AND [Day] = @MINDAY

            SELECT @POS = @POS + 1
        END

        SELECT @CURRENTYEAR = @CURRENTYEAR + 1
    END

    UPDATE DT
    SET HolidayText = 'Election Day'
    FROM [dbo].[DimDate] DT
    INNER JOIN #tmpHoliday HL ON (HL.DateID + 1) = DT.ID
    WHERE [Week] = 1

    DROP TABLE #tmpHoliday
END
GO

/*******************************************************************************************************************************************************/
CREATE UNIQUE NONCLUSTERED INDEX [IDXDimDateDate] ON [dbo].[DimDate] ([Date] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateDay] ON [dbo].[DimDate] ([Day] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateDayOfWeek] ON [dbo].[DimDate] ([DayOfWeek] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateDOWInMonth] ON [dbo].[DimDate] ([DOWInMonth] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateDayOfYear] ON [dbo].[DimDate] ([DayOfYear] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateWeekOfYear] ON [dbo].[DimDate] ([WeekOfYear] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateWeekOfMonth] ON [dbo].[DimDate] ([WeekOfMonth] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateMonth] ON [dbo].[DimDate] ([Month] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateMonthName] ON [dbo].[DimDate] ([MonthName] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateQuarter] ON [dbo].[DimDate] ([Quarter] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateQuarterName] ON [dbo].[DimDate] ([QuarterName] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDXDimDateYear] ON [dbo].[DimDate] ([Year] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDX_dim_Time_HolidayText] ON [dbo].[DimDate] ([HolidayText] 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
            ,FILLFACTOR = 90
            ) ON [PRIMARY]

SELECT *
FROM [dbo].[DimDate]
ORDER BY ID
Run Code Online (Sandbox Code Playgroud)

**问题是,查询不会创建从 1995 到 2025 的所有范围。**

Aar*_*and 12

假设 SQL Server 2008 或更高版本(请始终在您的问题中包含版本信息)。

我最近写了一个关于构建日历表的技巧,在这里:

但本着在这里提供更简洁答案的精神......

我会让你处理假期,但这里有一种更有效、基于集合的方法来生成 30 年的日期维度。你的很多CASE表达式、聚合、更新和循环根本没有必要,因为它们是用“单独处理每个单独的日期”的心态构建的。在数据库中,您希望尽可能多地考虑集合。它通常更有效,并且几乎总是简化代码。

DECLARE @StartDate DATE = '19950101', @NumberOfYears INT = 30;

SET DATEFIRST 7;
SET DATEFORMAT mdy;
SET LANGUAGE US_ENGLISH;

DECLARE @EndDate DATE = DATEADD(DAY,-1,DATEADD(YEAR,@NumberOfYears,@StartDate));

CREATE TABLE #dim
(
  dt DATE PRIMARY KEY, 
  d AS DATEPART(DAY, dt),
  y AS DATEPART(YEAR, dt),
  q AS DATEPART(QUARTER, dt),
  m AS DATEPART(MONTH, dt),
  fm AS DATEADD(MONTH, DATEDIFF(MONTH, 0, dt), 0), -- first of month
  w AS DATEPART(WEEK, dt), -- maybe you want ISO_WEEK?
  wd AS DATEPART(WEEKDAY, dt),
  mn AS DATENAME(MONTH, dt),
  s101 AS CONVERT(CHAR(10), dt, 101), -- mm/dd/yyyy
  s103 AS CONVERT(CHAR(10), dt, 103), -- dd/mm/yyyy
  s112 AS CONVERT(CHAR(8),  dt, 112)  -- yyyymmdd
);

INSERT #dim(dt) SELECT d FROM
(
  SELECT d = DATEADD(DAY, rn-1, @StartDate)
  FROM 
  (
    SELECT TOP (DATEDIFF(DAY,@StartDate,@EndDate)+1) 
      rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
    FROM sys.all_objects AS s1
    CROSS JOIN sys.all_objects AS s2
    -- on my system this would support > 5 million days
    ORDER BY s1.[object_id]
  ) AS x
) AS y;
Run Code Online (Sandbox Code Playgroud)

...只是为了分解代码块...

--INSERT dbo.DimDate(...)
SELECT
  ID = s112,
  [Date] = dt,
  StandardDate = s101,
  [Day] = LEFT(s103, 2),
  DaySuffix = CASE WHEN d / 10 = 1 THEN 'th' ELSE CASE RIGHT(d, 1) 
    WHEN '1' THEN 'st' 
    WHEN '2' THEN 'nd' 
    WHEN '3' THEN 'rd' 
    ELSE 'th' END END,
  [DayOfWeek]  = DATENAME(WEEKDAY, dt),
  [DOWInMonth] = ROW_NUMBER() OVER (PARTITION BY fm, wd ORDER BY dt),
  [DayOfYear]  = DATEPART(DAYOFYEAR, dt),
  WeekOfMonth  = DENSE_RANK() OVER (PARTITION BY y, m ORDER BY w),
  WeekOfYear   = w,
  [Month] = LEFT(s101, 2),
  [MonthName] = mn,
  [Quarter] = q,
  QuarterName = CASE q WHEN 1 THEN 'First'
    WHEN 2 THEN 'Second' WHEN 3 THEN 'Third'
    WHEN 4 THEN 'Fourth' END, 
  [Year] = y,
  MMYYYY = LEFT(s101, 2) + LEFT(s112, 4),
  MonthYear = LEFT(mn, 3) + LEFT(s112, 4),
  FirstDayOfMonth   = fm,
  LastDayOfMonth    = MAX(dt) OVER (PARTITION BY y, m),
  FirstDayOfQuarter = MIN(dt) OVER (PARTITION BY y, q),
  LastDayOfQuarter  = MAX(dt) OVER (PARTITION BY y, q),
  FirstDayOfYear    = MIN(dt) OVER (PARTITION BY y),
  LastDayOfYear     = MAX(dt) OVER (PARTITION BY y)
FROM #dim AS d
ORDER BY [Date]
OPTION (MAXDOP 1);

GO
DROP TABLE #dim;
Run Code Online (Sandbox Code Playgroud)

有关没有循环的生成集(以及原因)的更多信息,请参阅以下帖子:

StandardDate顺便说一句,我认为您的“ ”栏有点用词不当。在美国以外,mm/dd/yyyy远非标准;事实上,这是彻头彻尾的混乱。你的代码和表格设计还有一些其他方面可以使用注意力(包括你选择的DATETIME代替SMALLDATETIMEDATEVARCHAR(10)代替CHAR(8),使用VARCHAR无长度,懒惰的速记如wwandmm等);我建议阅读这些帖子:

如果您感到无聊,这里有一个更全面的清单: