如何创建只有SQL Server 2017每个月底的日历表
创建一个日历表或CTE以返回一年中每个月底日期的最简单方法是什么 大概是这样的:如何创建只有SQL Server 2017每个月底的日历表,sql,sql-server,tsql,Sql,Sql Server,Tsql,创建一个日历表或CTE以返回一年中每个月底日期的最简单方法是什么 大概是这样的: 也许不是最简单的方法,但最有效的方法是理货: WITH N AS( SELECT N FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)), Tally AS( SELECT ROW_NUMBER() OVER (ORDER BY (SELEC
也许不是最简单的方法,但最有效的方法是理货:
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
FROM N N1, N N2) --Add more for more months
SELECT DATEADD(MONTH, T.I, '20000101') AS MonthStart,
EOMOMTH(DATEADD(MONTH, T.I, '20000101')) AS MonthEnd
FROM Tally T;
在这种情况下,EOMONTH函数将起作用,请参见下面查询中的最后一个字段
DECLARE @StartDate DATETIME = '01/01/2015'
DECLARE @EndDate DATETIME = '12/01/2016'
;WITH OrderedDays as
(
SELECT CalendarDate = @StartDate
UNION ALL
SELECT CalendarDate = DATEADD(MONTH, 1, CalendarDate)
FROM OrderedDays WHERE DATEADD (MONTH, 1, CalendarDate) <= @EndDate
),
Calendar AS
(
SELECT
EndOfMonth = EOMONTH ( CalendarDate )
FROM
OrderedDays
)
SELECT * FROM Calendar
OPTION (MAXRECURSION 0)
您可以为此使用递归公共表表达式:
with cte as (
select cast('2018-01-31' as date) EndOfMonth
union all
select eomonth(dateadd(month, 1, EndOfMonth))
from cte
where EndOfMonth < cast('2018-12-01' as date)
)
select * from cte
编辑
正如@squillman所评论的:如果您计划生成7年以上的日历,那么您需要在查询末尾添加optionmaxrecursion 0子句
正如@Larnu所评论的:当数据集变得更大时,递归查询的性能确实会下降。如果您需要生成一个非常大的日历,比如几个世纪,那么其他选项更好
最后,如果你发现自己在查询中重复地生成日历表,那么你应该考虑实现日历,即将它存储在一个真实的数据库表中,然后你可以加入你的查询。这是数据库设计中广泛使用的解决方案,可使查询更简单、更高效。您可以使用建议的查询最初为表提供信息。U可以使用master..spt\U values系统表。下面是一段示例代码:
SELECT DATEADD([dd], -1, DATEFROMPARTS(2020, [number] + 1, 1))
FROM master..spt_values
WHERE [number] BETWEEN 1 AND 11
AND [type] = 'P'
UNION
SELECT dateadd(dd, -1, DATEFROMPARTS(2021, 1, 1))
编辑:好的,thx到@Ross Bush,有一个更好更小的代码:
SELECT EOMONTH(DATEFROMPARTS(2020, [number], 1))
FROM master..spt_values
WHERE [number] BETWEEN 1 AND 12
AND [type] = 'P'
我在不同的论坛上找到了这个答案,并用它为我的DWH创建了一个日历表 `
它应该能回答您和其他一些人的问题。您希望为哪一年/多少年生成它?如果能够提供日期范围,那就太好了。但是我想说5年了,很有趣。但可以修改它以生成月底数据吗?不是开头?我想我可以加上EOMONTHDATEADDMOUNT,T.I,'20000101',你可以在选择的行号中使用前N。。。语句,@Serdia和/或更改Tally中引用N的次数。如果您没有SQL 2017,则将EOMOMTH函数替换为DATEADDMONTH,t.I,DATEADDMONTH,1,DATEADDday,-1,'20000101'ASMonthEnd@KeithL您每月不需要SQL Server 2017,只需要一个受支持的版本即可。;放在你陈述的末尾,而不是放在前面。这是一个声明终结者,而不是开始者;谢谢你的花边新闻!旧习惯很难改掉。请注意,数据集越大,这种情况就会越慢。顾名思义,RCTE是递归的,SQL Server不擅长迭代任务+1,但要注意的是,如果不达到SQL Server 2017的最大递归深度,就不能超过7年。当你说更大的数据集时,您认为数据集应该在多少年后才会注意到性能缓慢?@Larnu:是的,我同意,在大型数据集上,性能会受到影响。但是对于像这里这样的一个小问题,我发现递归查询的简单性和灵活性克服了微小的性能差异。@Serdia:这取决于您的性能要求。。。作为猜测:在几百次或上千次迭代中,我并不期望有明显的差异。这个查询每年只进行12次迭代,这样就给了您长达几个世纪的空间。您需要在数据库中进行真实性测试。拉努请随时对此发表评论。
SELECT EOMONTH(DATEFROMPARTS(2020, [number], 1))
FROM master..spt_values
WHERE [number] BETWEEN 1 AND 12
AND [type] = 'P'
DECLARE @StartDate date = '20000101';
DECLARE @CutoffDate date = DATEADD(DAY, -1, DATEADD(YEAR, 50, @StartDate));
;WITH seq(n) AS
(
SELECT 0 UNION ALL
SELECT n + 1
FROM seq
WHERE n < DATEDIFF(DAY, @StartDate, @CutoffDate)
),
d(d) AS
(
SELECT DATEADD(DAY, n, @StartDate) FROM seq
),
src AS
(
SELECT
TheDate = CONVERT(date, d),
DateAsInteger = CONVERT(INT, format(d,'yyyyMMdd')),
TheDay = DATEPART(DAY, d),
TheDayName = DATENAME(WEEKDAY, d),
TheWeek = DATEPART(WEEK, d),
TheISOWeek = DATEPART(ISO_WEEK, d),
TheDayOfWeek = DATEPART(WEEKDAY, d),
TheMonth = DATEPART(MONTH, d),
TheMonthName = DATENAME(MONTH, d),
TheQuarter = DATEPART(Quarter, d),
TheYear = DATEPART(YEAR, d),
YearMonthnumber = CONVERT(INT, format(d,'yyyyMM')),
YearMonthShort = format(d,'yyyy-MMM'),
TheFirstOfMonth = DATEFROMPARTS(YEAR(d), MONTH(d), 1),
TheLASTOfMonth = EOMONTH(d),
TheLastOfYear = DATEFROMPARTS(YEAR(d), 12, 31),
TheDayOfYear = DATEPART(DAYOFYEAR, d)
FROM d
)
SELECT * into AN_Calendar FROM src
ORDER BY TheDate
OPTION (MAXRECURSION 0);`