如何在Sql中创build100年的日历表

假设我想在表格中存储数千天,我将如何从日历中检索它?

这是您可以在SQL Server中使用的通用脚本。 只是修改开始和结束date:

IF EXISTS (SELECT * FROM information_schema.tables WHERE Table_Name = 'Calendar' AND Table_Type = 'BASE TABLE') BEGIN DROP TABLE [Calendar] END CREATE TABLE [Calendar] ( [CalendarDate] DATETIME ) DECLARE @StartDate DATETIME DECLARE @EndDate DATETIME SET @StartDate = GETDATE() SET @EndDate = DATEADD(d, 365, @StartDate) WHILE @StartDate <= @EndDate BEGIN INSERT INTO [Calendar] ( CalendarDate ) SELECT @StartDate SET @StartDate = DATEADD(dd, 1, @StartDate) END 

如果你想要更高级的日历,那么我刚才在网上find了:

 CREATE SCHEMA Auxiliary -- We put our auxiliary tables and stuff in a separate schema -- One of the great new things in SQL Server 2005 go CREATE FUNCTION Auxiliary.Computus -- Computus (Latin for computation) is the calculation of the date of -- Easter in the Christian calendar -- http://en.wikipedia.org/wiki/Computus -- I'm using the Meeus/Jones/Butcher Gregorian algorithm ( @Y INT -- The year we are calculating easter sunday for ) RETURNS DATETIME AS BEGIN DECLARE @a INT, @b INT, @c INT, @d INT, @e INT, @f INT, @g INT, @h INT, @i INT, @k INT, @L INT, @m INT SET @a = @Y % 19 SET @b = @Y / 100 SET @c = @Y % 100 SET @d = @b / 4 SET @e = @b % 4 SET @f = (@b + 8) / 25 SET @g = (@b - @f + 1) / 3 SET @h = (19 * @a + @b - @d - @g + 15) % 30 SET @i = @c / 4 SET @k = @c % 4 SET @L = (32 + 2 * @e + 2 * @i - @h - @k) % 7 SET @m = (@a + 11 * @h + 22 * @L) / 451 RETURN(DATEADD(month, ((@h + @L - 7 * @m + 114) / 31)-1, cast(cast(@Y AS VARCHAR) AS Datetime)) + ((@h + @L - 7 * @m + 114) % 31)) END GO CREATE TABLE [Auxiliary].[Calendar] ( -- This is the calendar table [Date] datetime NOT NULL, [Year] int NOT NULL, [Quarter] int NOT NULL, [Month] int NOT NULL, [Week] int NOT NULL, [Day] int NOT NULL, [DayOfYear] int NOT NULL, [Weekday] int NOT NULL, [Fiscal_Year] int NOT NULL, [Fiscal_Quarter] int NOT NULL, [Fiscal_Month] int NOT NULL, [KindOfDay] varchar(10) NOT NULL, [Description] varchar(50) NULL, PRIMARY KEY CLUSTERED ([Date]) ) GO ALTER TABLE [Auxiliary].[Calendar] -- In Celkoish style I'm manic about constraints (Never use em ;-)) -- http://www.celko.com/ ADD CONSTRAINT [Calendar_ck] CHECK ( ([Year] > 1900) AND ([Quarter] BETWEEN 1 AND 4) AND ([Month] BETWEEN 1 AND 12) AND ([Week] BETWEEN 1 AND 53) AND ([Day] BETWEEN 1 AND 31) AND ([DayOfYear] BETWEEN 1 AND 366) AND ([Weekday] BETWEEN 1 AND 7) AND ([Fiscal_Year] > 1900) AND ([Fiscal_Quarter] BETWEEN 1 AND 4) AND ([Fiscal_Month] BETWEEN 1 AND 12) AND ([KindOfDay] IN ('HOLIDAY', 'SATURDAY', 'SUNDAY', 'BANKDAY'))) GO SET DATEFIRST 1; -- I want my table to contain datedata acording to ISO 8601 -- http://en.wikipedia.org/wiki/ISO_8601 -- thus first day of a week is monday WITH Dates(Date) -- A recursive CTE that produce all dates between 1999 and 2020-12-31 AS ( SELECT cast('1999' AS DateTime) Date -- SQL Server supports the ISO 8601 format so this is an unambigious shortcut for 1999-01-01 UNION ALL -- http://msdn2.microsoft.com/en-us/library/ms190977.aspx SELECT (Date + 1) AS Date FROM Dates WHERE Date < cast('2021' AS DateTime) -1 ), DatesAndThursdayInWeek(Date, Thursday) -- The weeks can be found by counting the thursdays in a year so we find -- the thursday in the week for a particular date AS ( SELECT Date, CASE DATEPART(weekday,Date) WHEN 1 THEN Date + 3 WHEN 2 THEN Date + 2 WHEN 3 THEN Date + 1 WHEN 4 THEN Date WHEN 5 THEN Date - 1 WHEN 6 THEN Date - 2 WHEN 7 THEN Date - 3 END AS Thursday FROM Dates ), Weeks(Week, Thursday) -- Now we produce the weeknumers for the thursdays -- ROW_NUMBER is new to SQL Server 2005 AS ( SELECT ROW_NUMBER() OVER(partition by year(Date) order by Date) Week, Thursday FROM DatesAndThursdayInWeek WHERE DATEPART(weekday,Date) = 4 ) INSERT INTO Auxiliary.Calendar SELECT d.Date, YEAR(d.Date) AS Year, DATEPART(Quarter, d.Date) AS Quarter, MONTH(d.Date) AS Month, w.Week, DAY(d.Date) AS Day, DATEPART(DayOfYear, d.Date) AS DayOfYear, DATEPART(Weekday, d.Date) AS Weekday, -- Fiscal year may be different to the actual year in Norway the are the same -- http://en.wikipedia.org/wiki/Fiscal_year YEAR(d.Date) AS Fiscal_Year, DATEPART(Quarter, d.Date) AS Fiscal_Quarter, MONTH(d.Date) AS Fiscal_Month, CASE -- Holidays in Norway -- For other countries and states: Wikipedia - List of holidays by country -- http://en.wikipedia.org/wiki/List_of_holidays_by_country WHEN (DATEPART(DayOfYear, d.Date) = 1) -- New Year's Day OR (d.Date = Auxiliary.Computus(YEAR(Date))-7) -- Palm Sunday OR (d.Date = Auxiliary.Computus(YEAR(Date))-3) -- Maundy Thursday OR (d.Date = Auxiliary.Computus(YEAR(Date))-2) -- Good Friday OR (d.Date = Auxiliary.Computus(YEAR(Date))) -- Easter Sunday OR (d.Date = Auxiliary.Computus(YEAR(Date))+39) -- Ascension Day OR (d.Date = Auxiliary.Computus(YEAR(Date))+49) -- Pentecost OR (d.Date = Auxiliary.Computus(YEAR(Date))+50) -- Whitmonday OR (MONTH(d.Date) = 5 AND DAY(d.Date) = 1) -- Labour day OR (MONTH(d.Date) = 5 AND DAY(d.Date) = 17) -- Constitution day OR (MONTH(d.Date) = 12 AND DAY(d.Date) = 25) -- Cristmas day OR (MONTH(d.Date) = 12 AND DAY(d.Date) = 26) -- Boxing day THEN 'HOLIDAY' WHEN DATEPART(Weekday, d.Date) = 6 THEN 'SATURDAY' WHEN DATEPART(Weekday, d.Date) = 7 THEN 'SUNDAY' ELSE 'BANKDAY' END KindOfDay, CASE -- Description of holidays in Norway WHEN (DATEPART(DayOfYear, d.Date) = 1) THEN 'New Year''s Day' WHEN (d.Date = Auxiliary.Computus(YEAR(Date))-7) THEN 'Palm Sunday' WHEN (d.Date = Auxiliary.Computus(YEAR(Date))-3) THEN 'Maundy Thursday' WHEN (d.Date = Auxiliary.Computus(YEAR(Date))-2) THEN 'Good Friday' WHEN (d.Date = Auxiliary.Computus(YEAR(Date))) THEN 'Easter Sunday' WHEN (d.Date = Auxiliary.Computus(YEAR(Date))+39) THEN 'Ascension Day' WHEN (d.Date = Auxiliary.Computus(YEAR(Date))+49) THEN 'Pentecost' WHEN (d.Date = Auxiliary.Computus(YEAR(Date))+50) THEN 'Whitmonday' WHEN (MONTH(d.Date) = 5 AND DAY(d.Date) = 1) THEN 'Labour day' WHEN (MONTH(d.Date) = 5 AND DAY(d.Date) = 17) THEN 'Constitution day' WHEN (MONTH(d.Date) = 12 AND DAY(d.Date) = 25) THEN 'Cristmas day' WHEN (MONTH(d.Date) = 12 AND DAY(d.Date) = 26) THEN 'Boxing day' END Description FROM DatesAndThursdayInWeek d -- This join is for getting the week into the result set inner join Weeks w on d.Thursday = w.Thursday OPTION(MAXRECURSION 0) GO CREATE FUNCTION Auxiliary.Numbers ( @AFrom INT, @ATo INT, @AIncrement INT ) RETURNS @RetNumbers TABLE ( [Number] int PRIMARY KEY NOT NULL ) AS BEGIN WITH Numbers(n) AS ( SELECT @AFrom AS n UNION ALL SELECT (n + @AIncrement) AS n FROM Numbers WHERE n < @ATo ) INSERT @RetNumbers SELECT n from Numbers OPTION(MAXRECURSION 0) RETURN; END GO CREATE FUNCTION Auxiliary.iNumbers ( @AFrom INT, @ATo INT, @AIncrement INT ) RETURNS TABLE AS RETURN( WITH Numbers(n) AS ( SELECT @AFrom AS n UNION ALL SELECT (n + @AIncrement) AS n FROM Numbers WHERE n < @ATo ) SELECT n AS Number from Numbers ) GO 
  declare @date int WITH CTE_DatesTable AS ( SELECT CAST('20000101' as date) AS [date] UNION ALL SELECT DATEADD(dd, 1, [date]) FROM CTE_DatesTable WHERE DATEADD(dd, 1, [date]) <= '21001231' ) SELECT [DWDateKey]=[date],[DayDate]=datepart(dd,[date]),[DayOfWeekName]=datename(dw,[date]),[WeekNumber]=DATEPART( WEEK , [date]),[MonthNumber]=DATEPART( MONTH , [date]),[MonthName]=DATENAME( MONTH , [date]),[MonthShortName]=substring(LTRIM( DATENAME(MONTH,[date])),0, 4),[Year]=DATEPART(YY,[date]),[QuarterNumber]=DATENAME(quarter, [date]),[QuarterName]=DATENAME(quarter, [date]) into DimDate FROM CTE_DatesTable OPTION (MAXRECURSION 0); 

这将快速为您创造结果。

 select top 100000 identity (int ,1,1) as Sequence into Tally from sysobjects , sys.all_columns select dateadd(dd,sequence,-1) Dates into CalenderTable from tally delete from CalenderTable where dates < -- mention the mindate you need delete from CalenderTable where dates > -- mention the max date you need 

第1步:创build一个序列表

第2步:使用序列表生成所需的date

第3步:删除不需要的date

这个SQL Server用户定义函数有效地解决了这个问题。没有recursion,没有复杂的循环。 这需要很短的时间来产生。

 ALTER FUNCTION [GA].[udf_GenerateCalendar] ( @StartDate DATE -- StartDate , @EndDate DATE -- EndDate ) RETURNS @Results TABLE ( Date DATE ) AS /********************************************************** Purpose: Generate a sequence of dates based on StartDate and EndDate ***********************************************************/ BEGIN DECLARE @counter INTEGER = 1 DECLARE @days table( day INTEGER NOT NULL ) DECLARE @months table( month INTEGER NOT NULL ) DECLARE @years table( year INTEGER NOT NULL ) DECLARE @calendar table( Date DATE NOT NULL ) -- Populate generic days SET @counter = 1 WHILE @counter <= 31 BEGIN INSERT INTO @days SELECT @counter dia SELECT @counter = @counter + 1 END -- Populate generic months SET @counter = 1 WHILE @counter <= 12 BEGIN INSERT INTO @months SELECT @counter month SELECT @counter = @counter + 1 END -- Populate generic years SET @counter = YEAR(@StartDate) WHILE @counter <= YEAR(@EndDate) BEGIN INSERT INTO @years SELECT @counter year SELECT @counter = @counter + 1 END INSERT @calendar (Date) SELECT Date FROM ( SELECT CONVERT(Date, [Date], 102) AS Date FROM ( SELECT CAST( y.year * 10000 + m.month * 100 + d.day AS VARCHAR(8)) AS Date FROM @days d, @months m, @years y WHERE ISDATE(CAST( y.year * 10000 + m.month * 100 + d.day AS VARCHAR(8)) ) = 1 ) A ) A INSERT @Results (Date) SELECT Date FROM @calendar WHERE Date BETWEEN @StartDate AND @EndDate RETURN /* DECLARE @StartDate DATE = '2015-08-01' DECLARE @EndDate DATE = '2015-08-31' select * from [GA].[udf_GenerateCalendar](@StartDate, @EndDate) */ END 

由于这只是标记的sql (这不表示任何特定的DBMS),这里是Postgres的解决scheme:

 select d::date from generate_series(date '1990-01-01', date '1990-01-01' + interval '100' year, interval '1' day) as t(d); 

如果你需要这么多,将其存储在一个表(可以被编入索引)中会更有效率:

 create table calendar as select d::date as the_date from generate_series(date '1990-01-01', date '1990-01-01' + interval '100' year, interval '1' day) as t(d);