两个日期之间的月份

时间:2011-10-25 07:15:41

标签: sql sql-server

是否可以在month names

中的两个日期之间获得SQl

即  2011-05-01 2011-08-01是输入 我只想输出

------------
Month
------------
May
June
July
August

如果有任何机构知道该查询,请分享。

9 个答案:

答案 0 :(得分:37)

DECLARE @StartDate  DATETIME,
        @EndDate    DATETIME;

SELECT   @StartDate = '20110501'        
        ,@EndDate   = '20110801';


SELECT  DATENAME(MONTH, DATEADD(MONTH, x.number, @StartDate)) AS MonthName
FROM    master.dbo.spt_values x
WHERE   x.type = 'P'        
AND     x.number <= DATEDIFF(MONTH, @StartDate, @EndDate);

结果:

MonthName
------------------------------
May
June
July
August

(4 row(s) affected)

答案 1 :(得分:29)

您可以使用递归CTE,通过构建日期表并从每个日期获取月份名称来执行此操作:

declare @start DATE = '2011-05-01'
declare @end DATE = '2011-08-01'

;with months (date)
AS
(
    SELECT @start
    UNION ALL
    SELECT DATEADD(month,1,date)
    from months
    where DATEADD(month,1,date)<=@end
)
select Datename(month,date) from months

答案 2 :(得分:8)

我已修改Jamiec's answer以输出该月的最后一天。

declare @start DATE = '2014-05-01'
declare @end DATE = getdate()

;with months (date)
AS
(
    SELECT @start
    UNION ALL
    SELECT DATEADD(month,1,date)
    from months
    where DATEADD(month,1,date) < @end
)
select     [MonthName]    = DATENAME(mm ,Date)  
            ,[MonthNumber]  = DATEPART(mm ,Date)  
            ,[LastDayOfMonth]  = DATEPART(dd,EOMONTH(Date))
            ,[MonthYear]    = DATEPART(yy ,Date) 
from months

提供输出:

MonthName   MonthNumber LastDayOfMonth  MonthYear
May         5           31              2014
June        6           30              2014
July        7           31              2014
August      8           31              2014
September   9           30              2014

答案 3 :(得分:2)

受到Jamiec's answer的启发,但从day更大到day来解决问题:

declare @start DATE
declare @end DATE 

SELECT  @start='2011-05-19' , @end='2011-08-15' 

;with months (date)
AS
(
   SELECT DATEADD(DAY,1,EOMONTH(@start,-1))
    UNION ALL
    SELECT DATEADD(month,1,date)
    from months
    where DATEADD(month,1,date) < EOMONTH(@end)
)
select Datename(month,date)
from months

答案 4 :(得分:1)

    declare @start DATE = '2011-05-30'
    declare @end DATE = '2011-06-10' 
   ;with months (date)
    AS
    (
        SELECT @start
        UNION ALL
        SELECT DATEADD(month,1,date)
        from months
        where DATEADD(month,1,date)<= DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@end)+1,0))
    )
    select Datename(month,date) from months

答案 5 :(得分:0)

那么, @bogdhan sahlean给出了一个很好的基于集合的解决方案,但考虑到年份范围为datedatetime2的数据类型0001-01-019999-12-31,将值限制为2048,来自MSDN

  

日期范围0001-01-01至9999-12-31

     

CE 1月1,1日至9999年12月31日

即使这是极端的情况,但值得了解。因为有一天有人试图投射170多年的时间:)

即使是最热烈的答案也没有满足一些优势 (当开始日期&gt;结束日期不会显示结束日期的月份时, 此外,默认情况下,100次执行后递归查询失败)。 并且还使用递归cte进行迭代,这在大量使用时是性能的。

现在,更好的解决方案(恕我直言)是使用日历表或计数表来生成两个日期之间的月份。如果无法创建表格,则可以使用更好的替代方法 Itzik ben Gans级联CTE生成数字表。(here) 哪个更快,没有逻辑,物理读取,没有工作台NADA

这是代码

DECLARE @start DATETIME2 = '00010101'
DECLARE @end DATETIME2 = '99991231'
;WITH lv0 AS (SELECT 0 g UNION ALL SELECT 0)
    ,lv1 AS (SELECT 0 g FROM lv0 a CROSS JOIN lv0 b) -- 4
    ,lv2 AS (SELECT 0 g FROM lv1 a CROSS JOIN lv1 b) -- 16
    ,lv3 AS (SELECT 0 g FROM lv2 a CROSS JOIN lv2 b) -- 256
    ,lv4 AS (SELECT 0 g FROM lv3 a CROSS JOIN lv3 b) -- 65,536
    ,lv5 AS (SELECT 0 g FROM lv4 a CROSS JOIN lv4 b) -- 4,294,967,296
    ,Tally (n) AS (SELECT 0 UNION SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM lv5)
SELECT DATENAME(YEAR,DATEADD(MONTH,N,@start)) AS [Year Part], DATENAME(MONTH,DATEADD(MONTH,n,@start)) AS [Month Part]
FROM Tally where N between 0 and DATEDIFF(mm,@start,@end)  
ORDER BY n;

注意:我已添加SELECT 0以从第0位开始数字

我的电脑中显示的性能是

Itzik方法

  

(119988行(s)受影响)

     

SQL Server执行时间:CPU时间= 187毫秒,已用时间= 706   女士。   SQL Server解析和编译时间:CPU时间= 0毫秒,已用时间=   0毫秒。

这里给出的一个递归解决方案需要一段时间

  

(119988行受影响)表&#39;工作台&#39;。扫描计数2,合乎逻辑   读取719923,物理读取0,预读取读取0,lob逻辑读取   0,lob物理读取0,lob预读读取0。

     

SQL Server执行时间:CPU时间= 890毫秒,已用时间=   1069毫秒。

理货表,日历表和itzik数字表之间的性能可能略有不同,但与您提供的所有日期范围的魅力相似。

答案 6 :(得分:0)

创建如下所示的数据库功能

CREATE FUNCTION [dbo].[DateRange] 
(@Identifier CHAR(1),@StartDate DATETIME,@EndDate DATETIME)
RETURNS @SelectedRange TABLE(Dates DATE) AS
 BEGIN

   ;WITH cteRange (DateRange) AS (
   SELECT @StartDate
     UNION ALL
   SELECT
     CASE
         WHEN Upper(@Identifier) = 'H' THEN DATEADD(hh, 1, DateRange)
         WHEN Upper(@Identifier) = 'D' THEN DATEADD(dd, 1, DateRange)
         WHEN Upper(@Identifier) = 'W' THEN DATEADD(ww, 1, DateRange)
         WHEN Upper(@Identifier) = 'M' THEN DATEADD(mm, 1, DateRange)
         WHEN Upper(@Identifier) = 'Y' THEN DATEADD(yy, 1, DateRange)
     END
   FROM cteRange
   WHERE DateRange <=
    CASE
        WHEN Upper(@Identifier) = 'H' THEN DATEADD(hh, -1, @EndDate)
        WHEN Upper(@Identifier) = 'D' THEN DATEADD(dd, -1, @EndDate)
        WHEN Upper(@Identifier) = 'W' THEN DATEADD(ww, -1, @EndDate)
        WHEN Upper(@Identifier) = 'M' THEN DATEADD(mm, -1, @EndDate)
        WHEN Upper(@Identifier) = 'Y' THEN DATEADD(yy, -1, @EndDate)
    END)
 INSERT INTO @SelectedRange (Dates) SELECT DateRange FROM cteRange
  OPTION (MAXRECURSION 3660);
RETURN
END

然后使用该函数,我们可以生成日期范围

SELECT * from dbo.DateRange('M','1953-01-01','2019-01-01')

如果要格式化输出,可以将结果存储在表变量中,如下例所示,

DECLARE @tblDateRange TABLE (AutoID INT IDENTITY(1,1),DateRange DATE)
INSERT INTO @tblDateRange SELECT * from dbo.DateRange('M','1953-01-01','2019-01-01')
SELECT 
LEFT(DATENAME(MONTH,DateRange),3) [MonthYearValue],YEAR(DateRange) AS [Year]
FROM @tblDateRange

根据我们的需要,我们可以更改

OPTION (MAXRECURSION 3660)

答案 7 :(得分:-1)

如果您的MonthNames表包含每个月的名称,则可以运行

SELECT MonthName FROM MonthNames WHERE MonthNumber BETWEEN Month(&date1) AND Month(&date2);

表MonthNames就像

MonthName,MonthNumber
1月1日 2月2日 3月3日

依旧......

答案 8 :(得分:-1)

试试这个:

declare 
       @sd date=getdate(),
       @ld date='2016-01-01'

select 
     Datename(month,dateadd(month,number,GETDATE())), 
     number
from master.dbo.spt_values 
where type='p' 
     and dateadd(month,number,GETDATE()) <= @ld