Get month names ordered using recursion

  • Nice thoughts and suggestions!! But My idea is to keep the SQL script very simple, instead of creating the monthname statically we can go with the dynamic way.

    Thanks,

    Karthik

  • The recursive CTE is used for generating rows - and it's a massively expensive way to do this. In 2K8 or higher, row constructors would be much cheaper

    VALUES((1),(2),...)

    In 2k5, a simple CTE would be much cheaper:

    SELECT 1 AS n UNION ALL SELECT 2 ...

    β€œWrite the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • Krtyknm (3/13/2012)


    Nice thoughts and suggestions!! But My idea is to keep the SQL script very simple, instead of creating the monthname statically we can go with the dynamic way.

    Euh...

    keep the SQL script very simple <> recursive CTE

    At least for most people that is true...

    Need an answer? No, you need a question
    My blog at https://sqlkover.com.
    MCSE Business Intelligence - Microsoft Data Platform MVP

  • I'm not sure dynamic is needed, since month names are not really going to change. I can think of eaiser ways to "localise" a site than that.

  • How about using the order by converting the month to a date...

    create table months (MonthName varchar (12))

    insert months values ('January')

    insert months values ('February')

    insert months values ('March')

    insert months values ('April')

    insert months values ('May')

    insert months values ('June')

    insert months values ('July')

    insert months values ('August')

    insert months values ('September')

    insert months values ('October')

    insert months values ('November')

    insert months values ('December')

    select * from months order by convert(date, '1 ' + monthName + ' 1900')

  • Goodness me, if you are going to type them all in, SSRS has a place for you to do that much more easily for any parameter list. πŸ˜‰

    If you want something general purpose to create a set of rows from nothing, then the original post is a good example.

  • An option:

    SELECT DATENAME(month, DATEADD(month, [number], 0)) [MonthName]

    , MONTH(DATEADD(month, [number], 0)) [MonthValue]

    FROM [master].[dbo].[spt_values]

    WHERE [type]='P'

    AND [number] BETWEEN 0 AND 11

    ORDER BY [number];

  • Koen Verbeeck (3/13/2012)


    And what if February doesn't have any data?

    Unless I am mistaken he had year and month separated so it wouldn't work checking for it until they are combined as input in this case.

  • dennis.hafstrom (3/13/2012)


    Koen Verbeeck (3/13/2012)


    And what if February doesn't have any data?

    Unless I am mistaken he had year and month separated so it wouldn't work checking for it until they are combined as input in this case.

    My point exactly. Now the end user can call up a report that doesn't contain any data.

    Frustrating πŸ™‚

    Need an answer? No, you need a question
    My blog at https://sqlkover.com.
    MCSE Business Intelligence - Microsoft Data Platform MVP

  • Hi you all.

    Well, I prefer to use a tally table. more clean.

  • alfredoapereira (3/13/2012)


    Hi you all.

    Well, I prefer to use a tally table. more clean.

    I prefer to use a calendar table, even more clean πŸ˜‰

    Need an answer? No, you need a question
    My blog at https://sqlkover.com.
    MCSE Business Intelligence - Microsoft Data Platform MVP

  • Re "The same SQL statement should also be reusable for other projects. "

    On any Production-level database, that would be enough reason to make sure you definitely did have a reference table. Say Ref_CalenderMonth_tbl (MonthNum tinyint, MonthName varchar(20))

    create procedure dbo.ListMonthNames_sp

    as

    select MonthNum , MonthName

    from Ref_CalenderMonth_tbl

    order by MonthNum

    go

    EXEC dbo.ListMonthNames_sp

    go

    Also, sooner or later, any system auditing or exception reporting will want to know about months that have no data. In which case, something like Ref_CalenderMonth_tbl becomes essential.

    This is such a small table, performance should not be a worry. In any case, if the same stored procedure is being used by several systems, SQL Server is likely to cache the results anyway.

  • If you insist on not using a calendar table, then this is better: -

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

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

    CTEMonth(MonNum) AS (SELECT TOP 12 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM t2 x, t2 y)

    SELECT MonNum,

    DATENAME(MONTH,DATEADD(MONTH,MonNum,0)- 1)[MonthName] -- function to list the monthname.

    FROM CTEMonth;

    Proof?

    SET NOCOUNT ON;

    DBCC FREEPROCCACHE;

    DBCC DROPCLEANBUFFERS;

    PRINT REPLICATE('-',80);

    PRINT 'Recursive CTE';

    PRINT REPLICATE('-',80);

    SET STATISTICS IO ON;

    SET STATISTICS TIME ON;

    WITH CTEMonth

    AS

    (

    SELECT 1 AS MonNum

    UNION ALL

    SELECT MonNum + 1 -- add month number to 1 recursively

    FROM CTEMonth

    WHERE MonNum < 12 -- just to restrict the monthnumber upto 12

    )

    SELECT

    MonNum,

    DATENAME(MONTH,DATEADD(MONTH,MonNum,0)- 1)[MonthName] -- function to list the monthname.

    FROM CTEMonth;

    SET STATISTICS TIME OFF;

    SET STATISTICS IO OFF;

    PRINT REPLICATE('-',80);

    DBCC FREEPROCCACHE;

    DBCC DROPCLEANBUFFERS;

    PRINT REPLICATE('-',80);

    PRINT 'Non-Recursive CTE';

    PRINT REPLICATE('-',80);

    SET STATISTICS IO ON;

    SET STATISTICS TIME ON;

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

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

    CTEMonth(MonNum) AS (SELECT TOP 12 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM t2 x, t2 y)

    SELECT MonNum,

    DATENAME(MONTH,DATEADD(MONTH,MonNum,0)- 1)[MonthName] -- function to list the monthname.

    FROM CTEMonth;

    SET STATISTICS TIME OFF;

    SET STATISTICS IO OFF;

    DBCC execution completed. If DBCC printed error messages, contact your system administrator.

    DBCC execution completed. If DBCC printed error messages, contact your system administrator.

    --------------------------------------------------------------------------------

    Recursive CTE

    --------------------------------------------------------------------------------

    Table 'Worktable'. Scan count 2, logical reads 73, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 1 ms.

    --------------------------------------------------------------------------------

    DBCC execution completed. If DBCC printed error messages, contact your system administrator.

    DBCC execution completed. If DBCC printed error messages, contact your system administrator.

    --------------------------------------------------------------------------------

    Non-Recursive CTE

    --------------------------------------------------------------------------------

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    Yes, there isn't much in it but every little bit counts.


    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/

  • I have to agree with Cadavre here.

    It's not just the performance in this case, rCTE's are expensive and shouldn't be used unless they're doing far more work than simply generating a set of rows.

    β€œWrite the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • For the purpose of displaying 12 values the use of a recursive CTE is fine. Performance won't be an issue. You are using the CTE to generate numbers 1 to 12. For the same thing you could use a tally table for example Jeff Moden's: http://www.sqlservercentral.com/articles/T-SQL/62867/. Then you would end up with equivalent:SELECT N MonNon,
    DATENAME(MONTH,DATEADD(MONTH,N,0)- 1)[MonthName] /* function to list the monthname. */
      FROM dbo.Tally
    WHERE N <= 12 ORDER BY N

Viewing 15 posts - 16 through 30 (of 129 total)

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