Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何创建只有SQL Server 2017每个月底的日历表_Sql_Sql Server_Tsql - Fatal编程技术网

如何创建只有SQL Server 2017每个月底的日历表

如何创建只有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

创建一个日历表或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 (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);`