Fetching the Months in the given Date Range

  • Hi All in one of my requirement i need to fetch the months in the given date range ex :

    -- input

    DECLARE @FromDate DATETIME = '2011-08-10',

    @ToDate DATETIME = '2011-10-31'

    -- output

    Select 'Aug 2010' Months union

    select 'Sept 2010' union

    select 'Oct 2010'

    Thanks & regards

    Deepak.A

  • probably more efficient ways, but this would do it:

    DECLARE @Months TABLE (MonthYear VARCHAR(20))

    DECLARE @DATE DATETIME

    SELECT @DATE = CONVERT(VARCHAR, @FromDate, 106)

    WHILE @DATE < @ToDate

    BEGIN

    INSERT @Months SELECT RIGHT(CONVERT(VARCHAR, @DATE, 106), 8)

    SET @DATE = DATEADD(mm, 1, @DATE)

    END

    SELECT * FROM @Months

    [font="Verdana"]Of course I'm grumpy, I'm a DBA.[/font]
    The Grumpy DBA[/url][/size]

  • Use a calendar table. I've done one on the fly here, for performance you'd be better off with a real table.

    DECLARE @FromDate DATETIME = '2011-08-10',

    @ToDate DATETIME = '2011-10-31'

    ;WITH t1 AS (SELECT 1 N UNION ALL SELECT 1 N),

    t2 AS (SELECT 1 N FROM t1 x, t1 y),

    t3 AS (SELECT 1 N FROM t2 x, t2 y),

    t4 AS (SELECT 1 N FROM t3 x, t3 y),

    tally AS (SELECT DATEADD(MONTH,ROW_NUMBER() OVER (ORDER BY (SELECT NULL)),0) AS cal_date

    FROM t4 x, t4 y)

    SELECT RIGHT(CONVERT(VARCHAR, cal_date, 106), 8)

    FROM tally

    WHERE cal_date >= DATEADD(DAY, 1, @FromDate - DAY(@FromDate) + 1) -1

    AND cal_date <= DATEADD(DAY, 1, @ToDate - DAY(@ToDate) + 1) -1


    Forever trying to learn
    My blog - http://www.cadavre.co.uk/
    For better, quicker answers on T-SQL questions, click on the following...http://www.sqlservercentral.com/articles/Best+Practices/61537/
    For better, quicker answers on SQL Server performance related questions, click on the following...http://www.sqlservercentral.com/articles/SQLServerCentral/66909/

  • Hi Guys , Thanks For your Reply

    Regards - Deepak

  • Following the footsteps of Mr. Jeff Moden, I believe this would be good enough

    DECLARE @StartDate DATETIME, @EndDate DATETIME, @MonthDiff INT

    SELECT @StartDate = '1901-08-10', @EndDate = '4850-10-31'

    SELECT @MonthDiff = DATEDIFF(MONTH, @StartDate, @EndDate)

    ;WITH E1(N) AS (

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1

    ), --10E+1 or 10 rows

    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows

    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows

    E5(N) AS (SELECT 1 FROM E2 a, E4 b), --1,000,000 rows max

    cteTally(N) AS (--==== This provides the "zero base" and limits the number of rows right up front

    -- for both a performance gain and prevention of accidental "overruns"

    SELECT 0 UNION ALL

    SELECT TOP (@MonthDiff) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E5

    )

    SELECT RIGHT(CONVERT(VARCHAR, DATEADD(MONTH , N, @StartDate), 106), 8) FROM [cteTally]

  • Usman Butt (11/17/2011)


    Following the footsteps of Mr. Jeff Moden, I believe this would be good enough

    DECLARE @StartDate DATETIME, @EndDate DATETIME, @MonthDiff INT

    SELECT @StartDate = '20091001', @EndDate = '20111101'

    SELECT @MonthDiff = DATEDIFF(MONTH, @StartDate, @EndDate)

    ;WITH E1(N) AS (

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1

    ), --10E+1 or 10 rows

    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows

    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max

    cteTally(N) AS (--==== This provides the "zero base" and limits the number of rows right up front

    -- for both a performance gain and prevention of accidental "overruns"

    SELECT 0 UNION ALL

    SELECT TOP (@MonthDiff) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4

    )

    SELECT DATENAME(MONTH, DATEADD(MONTH, N, @StartDate)) + ' ' + DATENAME(YEAR, DATEADD(MONTH, N, @StartDate)) FROM [cteTally]

    Try that with the following dates: -

    DECLARE @FromDate DATETIME = '1901-08-10',

    @ToDate DATETIME = '4850-10-31'

    Also, the OP wanted "Aug 2010", not "August 2010".

    Small perf test.

    BEGIN TRAN

    DECLARE @start DATETIME, @end DATETIME

    SET NOCOUNT ON

    DECLARE @FromDate DATETIME = '1901-08-10',

    @ToDate DATETIME = '4850-10-31'

    PRINT '========== LOOP =========='

    SET @start = GETDATE()

    DECLARE @Months TABLE (MonthYear VARCHAR(20))

    DECLARE @DATE DATETIME

    SELECT @DATE = CONVERT(VARCHAR, @FromDate, 106)

    WHILE @DATE < @ToDate

    BEGIN

    INSERT @Months SELECT RIGHT(CONVERT(VARCHAR, @DATE, 106), 8)

    SET @DATE = DATEADD(mm, 1, @DATE)

    END

    SELECT * FROM @Months

    SET @end = GETDATE()

    PRINT DATEDIFF(MILLISECOND,@start,@end)

    PRINT REPLICATE('=',80)

    PRINT '========== CALENDER TALLY =========='

    SET @start = GETDATE()

    ;WITH t1 AS (SELECT 1 N UNION ALL SELECT 1 N),

    t2 AS (SELECT 1 N FROM t1 x, t1 y),

    t3 AS (SELECT 1 N FROM t2 x, t2 y),

    t4 AS (SELECT 1 N FROM t3 x, t3 y),

    tally AS (SELECT DATEADD(MONTH,ROW_NUMBER() OVER (ORDER BY (SELECT NULL)),0) AS cal_date

    FROM t4 x, t4 y)

    SELECT RIGHT(CONVERT(VARCHAR, cal_date, 106), 8)

    FROM tally

    WHERE cal_date >= DATEADD(DAY, 1, @FromDate - DAY(@FromDate) + 1) -1

    AND cal_date <= DATEADD(DAY, 1, @ToDate - DAY(@ToDate) + 1) -1

    SET @end = GETDATE()

    PRINT DATEDIFF(MILLISECOND,@start,@end)

    PRINT REPLICATE('=',80)

    ROLLBACK

    ========== LOOP ==========

    766

    ================================================================================

    ========== CALENDER TALLY ==========

    210

    ================================================================================

    Calendar tally table is faster than the loop, but you have to get into stupidly ridiculous dates to notice the difference.


    Forever trying to learn
    My blog - http://www.cadavre.co.uk/
    For better, quicker answers on T-SQL questions, click on the following...http://www.sqlservercentral.com/articles/Best+Practices/61537/
    For better, quicker answers on SQL Server performance related questions, click on the following...http://www.sqlservercentral.com/articles/SQLServerCentral/66909/

  • Told you there was a more efficient way of doing it 🙂

    [font="Verdana"]Of course I'm grumpy, I'm a DBA.[/font]
    The Grumpy DBA[/url][/size]

  • Cadavre (11/17/2011)


    Usman Butt (11/17/2011)


    Following the footsteps of Mr. Jeff Moden, I believe this would be good enough

    DECLARE @StartDate DATETIME, @EndDate DATETIME, @MonthDiff INT

    SELECT @StartDate = '20091001', @EndDate = '20111101'

    SELECT @MonthDiff = DATEDIFF(MONTH, @StartDate, @EndDate)

    ;WITH E1(N) AS (

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL

    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1

    ), --10E+1 or 10 rows

    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows

    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max

    cteTally(N) AS (--==== This provides the "zero base" and limits the number of rows right up front

    -- for both a performance gain and prevention of accidental "overruns"

    SELECT 0 UNION ALL

    SELECT TOP (@MonthDiff) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4

    )

    SELECT DATENAME(MONTH, DATEADD(MONTH, N, @StartDate)) + ' ' + DATENAME(YEAR, DATEADD(MONTH, N, @StartDate)) FROM [cteTally]

    Try that with the following dates: -

    DECLARE @FromDate DATETIME = '1901-08-10',

    @ToDate DATETIME = '4850-10-31'

    I know the limits which by the way was highlighted in form of comments that it is for 10000 maximum rows. But I will remind you your own words "you have to get into stupidly ridiculous dates" 😉

    Also, the OP wanted "Aug 2010", not "August 2010".

    Yes, I agree that but it should not be a major issue for the OP. I have changed my original answer for it.

    Small performance test of mine.

    When I ran both the solutions (I have changed mine a bit) for dates "@FromDate = '1901-08-10' , @ToDate = '4850-10-31'". My solution seems to be better than your solution when I saw the execution plan. You can test it yourself. Besides following was time statistics for my solution

    (35391 row(s) affected)

    SQL Server Execution Times:

    CPU time = 47 ms, elapsed time = 623 ms.

    Whereas, your solution's time statistics were

    (35391 row(s) affected)

    SQL Server Execution Times:

    CPU time = 63 ms, elapsed time = 896 ms.

    Cheers.

Viewing 8 posts - 1 through 7 (of 7 total)

You must be logged in to reply to this topic. Login to reply