【问题标题】:TSQL get last day of previous months upto a specified monthTSQL获取前几个月的最后一天直到指定月份
【发布时间】:2016-09-06 15:15:24
【问题描述】:

我需要获取包括当前月份在内的所有前几个月的最后一天,直到指定月份。例如,我需要 2015 年 9 月、8 月、7 月、6 月、5 月、4 月、3 月、2 月、1 月、12 月的最后几天,如下所示:

temptable_mytable

last_day_of_month
-----------------
2016-09-30
2016-08-31
2016-07-31
2016-06-30
2016-05-31
2016-04-30
2016-03-31
2016-02-30
2016-01-31
2015-12-31

我需要指定要返回的月份和年份 - 在上述情况下是 2015 年 12 月,但也可能是 2015 年 9 月等。有没有一种方法可以让我循环并执行此操作,而不必为每个月末单独计算?

【问题讨论】:

    标签: sql-server tsql


    【解决方案1】:

    将递归 CTE 与 EOMONTH 函数结合使用。

    DECLARE @startdate DATE = '2016-01-01'
    
    ;WITH CTE
    AS
    (
        SELECT EOMONTH(GETDATE()) as 'Dates'
        UNION ALL
        SELECT EOMONTH(DATEADD(MONTH, -1, [Dates]))
        FROM CTE WHERE Dates > DATEADD(MONTH, 1, @startdate)
    )
    
    SELECT * FROM CTE
    

    【讨论】:

    • 你的答案是第一个并且它有效,但我对上述如何变成“递归”感到有点困惑?换句话说,实际的“循环/递归”是如何/在哪里发生的?
    • CTE 定义中查询的第二部分是递归发生的地方。 CTE 中从 CTE 中选择的部分 :)
    • 感谢杰夫的解释!
    【解决方案2】:

    with temp as (select -1 i union all select i+1 i from temp where i < 8) select DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+i*-1,0)) from temp

    【讨论】:

      【解决方案3】:
      declare @LASTMONTH date = '2018-10-01';
      
      
      WITH MTHS AS (
                      SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday
                      UNION ALL
                      SELECT DATEADD(month,1,aday) from MTHS WHERE  aday <= @LASTMONTH
                      ),
          LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)     
      select * from LASTDAYS 
      

      这里是一个适当的向前或向后的版本

      declare @LASTMONTH date = '2013-10-01';
      
      
      WITH DIF AS (SELECT CASE WHEN 
                              YEAR(@LASTMONTH) * 12 + MONTH(@LASTMONTH) 
                              >= YEAR(GETDATE()) * 12 + MONTH(getdate()) THEN 1 ELSE -1 END x),
      MTHS AS (
                      SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday 
                      UNION ALL
                      SELECT DATEADD(month,(SELECT X from dif),aday) from MTHS 
                              WHERE  month(aday)  !=  month(dateadd(month,1,@LASTMONTH)) or YEAR(aday) != YEAR(dateadd(month,1,@LASTMONTH))
                      ),
          LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)     
      select * from LASTDAYS order by finaldayofmonth 
      

      【讨论】:

      • 我需要它返回而不是前进,但如果将来出现这种情况,您的查询可能会有所帮助。为此 +1。
      【解决方案4】:

      这是一种方法,使用 CTE 生成递增数字列表,以便我们可以从中选择并在 DATEADD 中使用以返回适当的月数。

      通常,如果您经常这样做,而不是像这样使用 CROSS JOIN 即时生成数字,我建议您只创建一个“数字”表,其中仅包含从 1 到“某个数字高”的数字足以满足您的需求”

      DECLARE @Date DATE = '20151201'
      DECLARE @MonthsBackToGo INTEGER
      SELECT @MonthsBackToGo = DATEDIFF(mm, @Date, GETDATE()) + 1;
      
      WITH _Numbers AS
      (
      SELECT TOP (@MonthsBackToGo) ROW_NUMBER() OVER (ORDER BY o.object_id) AS Number
          FROM sys.objects o
              CROSS JOIN sys.objects  o2
      )
      
      SELECT  EOMONTH(DATEADD(mm, -(Number- 1), GETDATE())) AS last_day_of_month
      FROM _Numbers
      

      【讨论】:

        【解决方案5】:

        无论您为原始表或对象后退或前进多远,这都应该向外扩展。

        SET NOCOUNT ON;
        
        DECLARE @Dates TABLE ( dt DATE)
        
        DECLARE @Start DATE = DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
        DECLARE @End DATE = DATEADD(YEAR, 1, @Start)
        
        WHILE @Start <= @End
        BEGIN
            INSERT INTO @Dates (dt) VALUES (@Start)
        
                SELECT @Start = DATEADD(DAY, 1, @Start)
        END
        
        
        ; With x as 
            (
            Select 
                dt
            ,   ROW_NUMBER() OVER(PARTITION BY DATEPART(YEAR, Dt), DATEPART(MONTH, Dt) ORDER BY Dt Desc) AS rwn
         From @Dates
        )
        Select *
        From x
        WHERE rwn = 1
        ORDER BY Dt
        

        【讨论】:

          【解决方案6】:

          这是根据几个不同的 SO 答案快速拼凑在一起的:

          DECLARE @startdate datetime, @enddate datetime
          
          set @startdate = '2015-12-01'
          set @enddate = getdate()
          
          ;WITH T(date)
          AS
          ( 
          SELECT @startdate
          UNION ALL
          SELECT DateAdd(day,1,T.date) FROM T WHERE T.date < @enddate
          )
          SELECT DISTINCT
          DATEADD(
              day, 
              -1,
              CAST(CAST(YEAR(date) AS varchar) + '-' + CAST(MONTH(date)AS varchar) + '-01' AS DATETIME))
          FROM T OPTION (MAXRECURSION 32767);
          

          【讨论】:

            猜你喜欢
            • 2019-05-03
            • 2021-07-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-10-17
            • 1970-01-01
            相关资源
            最近更新 更多