如何获得所选月份之间的第一个日期和最后日期?

时间:2016-06-09 13:41:51

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

如何获得所选月份之间的第一个日期和最后日期?

例如我输入2015年和09年至2016年08月

返回值必须为:

StartDate EndDate   
20150901 20150930  
20151001 20151031  
20151101 20151130  
20151201 20151231  
20160101 20160131  
20160201 20160229  
20160301 20160331   
20160401 20160430      
20160501 20160531   
20160601 20160630   
20160701 20160731   
20160801 20160831   

我发现多个查询执行相同但只插入1个日期。例如:

DECLARE @mydate DATETIME
SELECT @mydate = GETDATE()
SELECT CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(@mydate)-1),@mydate),101) AS Date_Value,
'First Day of Current Month' AS Date_Type
UNION

SELECT CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,@mydate))),DATEADD(mm,1,@mydate)),101) ,
'Last Day of Current Month'

但我无法找到一个可以为Between语句

执行此操作的人

4 个答案:

答案 0 :(得分:1)

我有两个udf可以单独使用或联合使用。它们使用可变的dateparts和/或增量动态创建日期范围。

Select * from [dbo].[udf-Create-Range-Date-Span]('2015-09-01','2016-08-01','MM',1) 

DateR1                  DateR2
2015-09-01 00:00:00.000 2015-10-01 00:00:00.000
2015-10-01 00:00:00.000 2015-11-01 00:00:00.000
2015-11-01 00:00:00.000 2015-12-01 00:00:00.000
2015-12-01 00:00:00.000 2016-01-01 00:00:00.000
2016-01-01 00:00:00.000 2016-02-01 00:00:00.000
2016-02-01 00:00:00.000 2016-03-01 00:00:00.000
2016-03-01 00:00:00.000 2016-04-01 00:00:00.000
2016-04-01 00:00:00.000 2016-05-01 00:00:00.000
2016-05-01 00:00:00.000 2016-06-01 00:00:00.000
2016-06-01 00:00:00.000 2016-07-01 00:00:00.000
2016-07-01 00:00:00.000 2016-08-01 00:00:00.000

现在,我专门使用上限,这样我就可以查询DateR1和DateR2之间的数据(包括时间)和

但是,稍微扭曲一下,就可以改变输出。例如:

Select DateR1=cast(DateR1 as Date),DateR2=DateAdd(DD,-1,cast(DateR2 as Date)) from [dbo].[udf-Create-Range-Date-Span]('2015-09-01','2016-08-01','MM',1) 

DateR1      DateR2
2015-09-01  2015-09-30
2015-10-01  2015-10-31
2015-11-01  2015-11-30
2015-12-01  2015-12-31
2016-01-01  2016-01-31
2016-02-01  2016-02-29
2016-03-01  2016-03-31
2016-04-01  2016-04-30
2016-05-01  2016-05-31
2016-06-01  2016-06-30
2016-07-01  2016-07-31

这两个功能如下:

CREATE FUNCTION [dbo].[udf-Create-Range-Date] (@DateFrom datetime,@DateTo datetime,@DatePart varchar(10),@Incr int)

Returns 
@ReturnVal Table (RetVal datetime)

As
Begin
    With DateTable As (
        Select DateFrom = @DateFrom
        Union All
        Select Case @DatePart
               When 'YY' then DateAdd(YY, @Incr, df.dateFrom)
               When 'QQ' then DateAdd(QQ, @Incr, df.dateFrom)
               When 'MM' then DateAdd(MM, @Incr, df.dateFrom)
               When 'WK' then DateAdd(WK, @Incr, df.dateFrom)
               When 'DD' then DateAdd(DD, @Incr, df.dateFrom)
               When 'HH' then DateAdd(HH, @Incr, df.dateFrom)
               When 'MI' then DateAdd(MI, @Incr, df.dateFrom)
               When 'SS' then DateAdd(SS, @Incr, df.dateFrom)
               End
        From DateTable DF
        Where DF.DateFrom < @DateTo
    )

    Insert into @ReturnVal(RetVal) Select DateFrom From DateTable option (maxrecursion 32767)

    Return
End

CREATE FUNCTION [dbo].[udf-Create-Range-Date-Span] (@Date1 datetime,@Date2 datetime,@DatePart varchar(10),@Incr int)

-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2020-10-01','YY',1) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-01-01','2016-12-31','MM',1) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2016-10-31','MI',15) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2016-10-02','SS',1) 

Returns Table 

As
Return (

     Select DateR1 = RetVal
           ,DateR2 = LEAD(RetVal,1,@Date2) OVER (ORDER BY RetVal)
     From (Select * from [dbo].[udf-Create-Range-Date](@Date1,@Date2,@DatePart,@Incr) ) A
     Where RetVal<@Date2

)

答案 1 :(得分:1)

您不需要UDF - 您可以使用单个查询执行此操作:

Declare @FromYear   Int = 2015,
        @FromMonth  Int = 9,
        @ToYear     Int = 2016,
        @ToMonth    Int = 8

Declare @FromDate   Date = (Select DateAdd(Year, @FromYear - 1900, DateAdd(Month,  @FromMonth - 1, 0))),
        @ToDate     Date = (Select DateAdd(Year, @ToYear - 1900, DateAdd(Month, @ToMonth - 1, 0)))

;With Date (Date) As
(
    Select  @FromDate Union All
    Select  DateAdd(Month, 1, Date)
    From    Date
    Where   Date < @ToDate
)
Select  Convert(Varchar, Year(Date)) + Right('00' + Convert(Varchar, Month(Date)), 2) + Right('00' + Convert(Varchar, Day(Date)), 2)    As StartDate,
        Convert(Varchar, Year(Date)) + Right('00' + Convert(Varchar, Month(Date)), 2) + Right('00' + Convert(Varchar, Day(DateAdd(Day, -1, DateAdd(Month, DateDiff(Month, 0, Date) + 1, 0)))), 2)   As EndDate 
From    Date
Option  (MaxRecursion 0)
  

输出

StartDate   EndDate
20150901    20150930
20151001    20151031
20151101    20151130
20151201    20151231
20160101    20160131
20160201    20160229
20160301    20160331
20160401    20160430
20160501    20160531
20160601    20160630
20160701    20160731
20160801    20160831

但是,如果您能够迁移到SQL Server 2012或更高版本,则查询会更简单:

Declare @FromYear   Int = 2015,
        @FromMonth  Int = 9,
        @ToYear     Int = 2016,
        @ToMonth    Int = 8

Declare @FromDate   Date    = DateFromParts(@FromYear, @FromMonth, 1),
        @ToDate     Date    = DateFromParts(@ToYear, @ToMonth, 1)

;With Date (Date) As
(
    Select  @FromDate Union All
    Select  DateAdd(Month, 1, Date)
    From    Date
    Where   Date < @ToDate
)
Select  Format(Date, N'yyyyMMdd')           As StartDate, 
        Format(EoMonth(Date), N'yyyyMMdd')  As EndDate
From    Date
Option  (MaxRecursion 0)

答案 2 :(得分:0)

试试这个。它也是一个非常小的脚本。我喜欢Siyual的CTE概念。但这要短得多。

DECLARE @inputYear INT = 2015,
@inputMonth INT = 09

SELECT DATEADD(MONTH, @inputMonth-1, DATEADD(YEAR, @inputYear-1900, 0)) AS FirstDayOfTheMonth,
DATEADD(s,-1, DATEADD(MONTH, @inputMonth, DATEADD(YEAR, @inputYear-1900, 0))) AS LastDayOfTheMonth 

答案 3 :(得分:-1)

使用一个ANSI sql语句也可以完成任务。 但是,您需要两个表ALL_YEARS和ALL_MONTHS,其中包含已使用的年和月集。

E.g。如果考虑1900年到2099年之间的可能年份,表ALL_YEARS必须包含1900年到2099年之间的数字。 表ALL_MONTHS必须包含1到12之间的数字。

使用这两个表,该语句如下所示:

select            to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy') first_day ,
       add_months(to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy'), 1) -1 last_day
from   all_years,
       all_months
where  to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy') between 
        to_date('01.02.2014', 'dd.mm.yyyy') and 
        to_date('01.07.2016', 'dd.mm.yyyy');

输出如下:

01.02.14    28.02.14
01.03.14    31.03.14
01.04.14    30.04.14
01.05.14    31.05.14
01.06.14    30.06.14
...
01.06.16    30.06.16
01.07.16    31.07.16