【问题标题】:tsql: How to retrieve the last date of each month between given date rangetsql:如何在给定日期范围内检索每个月的最后日期
【发布时间】:2013-09-18 09:59:35
【问题描述】:

我有两个日期,例如 2013 年 8 月 8 日和 2013 年 11 月 11 日,我需要从 8 月到 11 月在表格中每个月的最后一个日期,以便我可以遍历表格以单独选择这些日期。

我知道如何选择任何月份的最后日期,但我被日期范围困住了。

请提供帮助,我们将不胜感激。

注意:我使用的是 Sql 2008,日期范围也可以是 1 个月、2 个月或 6 个月或一年或最长。

【问题讨论】:

标签: sql sql-server sql-server-2008


【解决方案1】:

您可以使用CTE 获取指定范围内的所有最后几天

Declare @Start datetime
Declare @End datetime

Select @Start = '20130808'
Select @End = '20131111'
;With CTE as
(
Select @Start  as Date,Case When DatePart(mm,@Start)<>DatePart(mm,@Start+1) then 1 else 0 end as [Last]
UNION ALL
Select Date+1,Case When DatePart(mm,Date+1)<>DatePart(mm,Date+2) then 1 else 0 end from CTE
Where Date<@End
)

Select * from CTE
where [Last]=1   OPTION ( MAXRECURSION 0 )

【讨论】:

    【解决方案2】:
    DECLARE @tmpTable table (LastDates DATE);
    DECLARE @startDate DATE = '01/01/2012'; --1 Jan 2012
    DECLARE @endDate DATE = '05/31/2012';   --31 May 2012
    DECLARE @tmpEndDate DATE;
    
    SET @startDate = DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@startDate)+1,1));
    SET @tmpEndDate = DATEADD(DAY, 1, @endDate);
    
    WHILE (@startDate <= @tmpEndDate)
    BEGIN   
        INSERT INTO @tmpTable (LastDates) values (DATEADD(DAY, -1, @startDate));
        SET @startDate = DATEADD(MONTH, 1, @startDate);
    END
    
    SELECT [LastDates] FROM @tmpTable;
    

    输出:

    示例:1

    @startDate DATE = '01/01/2012'; --1 Jan 2012
    @endDate DATE = '05/31/2012';   --31 May 2012
    
    LastDates
    ----------
    2012-01-31
    2012-02-29
    2012-03-31
    2012-04-30
    2012-05-31
    

    示例:2

    @startDate DATE = '11/01/2011'; --1 Nov 2011
    @endDate DATE = '03/13/2012';   --13 Mar 2012
    
    LastDates
    ----------
    2011-11-30
    2011-12-31
    2012-01-31
    2012-02-29
    

    【讨论】:

    • 非常好的性能。它将每月仅迭代 1 条记录。
    【解决方案3】:

    我创建了一个表变量,用@startDate@endDate 之间的所有日期填充它,并搜索该月的最大日期。

    declare @tmpTable table (dates date)
    declare @startDate date = '08/08/2013'
    declare @endDate date = '11/11/2013'
    
    while @startDate <= @endDate
    begin
        insert into @tmpTable (dates) values (@startDate)
        set @startDate = DATEADD(DAY, 1, @startDate)
    end
    
    select max(dates) as [Last day] from @tmpTable as o
    group by datepart(YEAR, dates), datepart(MONTH, dates)
    

    结果:

    Last day
    2013-08-31
    2013-09-30
    2013-10-31
    2013-11-11
    

    要获得 11 月的最后一天,这可以在循环之前使用:

    set @endDate = DATEADD(day, -1, DATEADD(month, DATEDIFF(month, 0, @endDate) + 1, 0))
    

    【讨论】:

      【解决方案4】:

      以下脚本演示了查找上个月、当前和下个月的最后一天的脚本。

      ----Last Day of Previous Month
      SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
      LastDay_PreviousMonth
      ----Last Day of Current Month
      SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
      LastDay_CurrentMonth
      ----Last Day of Next Month
      SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
      LastDay_NextMonth
      

      如果您想查找指定日期的一个月的最后一天,请使用以下脚本。

      --Last Day of Any Month and Year
      DECLARE @dtDate DATETIME
      SET @dtDate = '8/18/2007'
      SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@dtDate)+1,0))
      LastDay_AnyMonth
      ResultSet:
      LastDay_AnyMonth
      

      源 - SQL Server Central。

      【讨论】:

        【解决方案5】:

        您可以使用递归 CTE 来执行此操作,注意 MAXRECURSION OPTION 可防止无限循环:

        DECLARE @StartDate DATE = '2013-08-08'
        DECLARE @EndDate DATE = '2013-11-11'
        
        ;WITH dateCTE
        AS
        (
            SELECT CAST(DATEADD(M, 1,DATEADD(d, DAY(@StartDate) * -1, @StartDate)) AS DATE) EndOFMonth
            UNION ALL 
            SELECT CAST(DATEADD(M, 2,DATEADD(d, DAY(EndOFMonth) * -1, EndOFMonth)) AS DATE) 
            FROM dateCTE
            WHERE EndOFMonth < DATEADD(d, DAY(@EndDate) * -1, @EndDate)
        
        )
        SELECT *
        FROM dateCTE
        OPTION (MAXRECURSION 30);
        

        返回

        EndOFMonth
        ----------
        2013-08-31
        2013-09-30
        2013-10-31
        

        【讨论】:

          【解决方案6】:

          试试这个 最后一行(where)对于日期过滤是可选的

          declare @table table  
          (  
          thisdate date  
          )
          
          
          insert into @table values ('12/01/2013'),('05/06/2013'),('04/29/2013'),('02/20/2013')
          select *,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,thisdate)+1,0))
          LastDay from @table
          where thisdate between 'givendate' and 'givendate'
          

          以下示例适用于所有日期

          thisdate    lastday
          2013-12-01  2013-12-31 23:59:59.000
          2013-05-06  2013-05-31 23:59:59.000
          2013-04-29  2013-04-30 23:59:59.000
          2013-02-20  2013-02-28 23:59:59.000
          

          【讨论】:

            【解决方案7】:

            以下 CTE 为您提供从 1900 年 2 月到 26 世纪中叶每个月的最后一天(在我的机器上):

            ;with LastDaysOfMonths as (
                select DATEADD(month,
                             ROW_NUMBER() OVER (ORDER BY so.object_id),
                             '19000131') as Dt
                from sys.objects so,sys.objects so1
            )
            select * from LastDaysOfMonths
            

            应该很容易将其用作更大查询的一部分或将其过滤到您想要的日期。您可以根据需要通过更改常量19000131 来调整年份范围。唯一需要做的重要事情是确保您使用的月份包含 31 天,并且始终保持第 31 天的常量。

            【讨论】:

              【解决方案8】:

              无需使用公用表表达式或类似的东西 - 这个简单的查询就可以做到:

              SELECT  DATEADD(d, -1, DATEADD(mm, DATEDIFF(m, 0, DATEADD(m, number, '2013-08-08')) + 1, 0)) AS EndOfMonth
              FROM    master.dbo.spt_values
              WHERE   'P' = type
                      AND DATEADD(m, number, '2013-08-08') < '2013-11-11';
              

              【讨论】:

                【解决方案9】:

                虽然问题是关于@bummi 已经回答的最后一天。

                但这是第一次约会的解决方案,可能对某人有所帮助。

                获取@FromDate@ToDate 之间所有月份的第一个日期。

                DECLARE @FromDate DATETIME = '2019-08-13'
                DECLARE @ToDate DATETIME = '2019-11-25'
                
                ;WITH CTE
                AS 
                (
                    SELECT DATEADD(DAY, -(DAY(@FromDate) - 1), @FromDate) AS FirstDateOfMonth
                
                    UNION ALL
                
                    SELECT DATEADD(MONTH, 1, FirstDateOfMonth)
                    FROM CTE
                    WHERE FirstDateOfMonth < DATEADD(DAY, -(DAY(@ToDate) - 1), @ToDate)
                )
                SELECT * FROM CTE
                

                这是结果

                --Result
                2019-08-01 00:00:00.000
                2019-09-01 00:00:00.000
                2019-10-01 00:00:00.000
                2019-11-01 00:00:00.000
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2017-02-23
                  • 1970-01-01
                  • 2019-02-25
                  • 2019-06-23
                  • 2021-01-08
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-12-05
                  相关资源
                  最近更新 更多