Increment a date T-SQL Statement

  • Hi

    Can anyone help me write a store procedure to increment a month

    For example

    The current month is January 10 I want to show the last 12 months so from January 10 - December 10.

    Now if the current month is February 10 I want to increment it to show from February 10 - January 11 and so on

    Jan 10, Feb 10, Mar 10, April 10 , May 10, June 10, July 10, Aug 10, Sep 10, Oct 10, Nov 10, Dec 10

    Can anyone help me or provide me with similar examples??

    Thanks in advance

    __________________________________________________________________________________
    Steve J
    Jnr Developer
    BSc(Hon)

  • Is this a homework question? I ask because I answered something almost identical to this a couple of days ago (here). . .

    One way would be to do it like this: -

    DECLARE @date DATETIME, @number INT

    SET @date = '2011-06-06 00:00:00'

    SET @number = 12

    ;WITH CTE AS (

    SELECT 0 AS months

    UNION ALL

    SELECT months + 1

    FROM CTE

    WHERE months < @number-1)

    SELECT DATEADD(MONTH,months,@date)

    FROM CTE

    You would need to format the result as you require.


    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 skcadavre,

    Thanks for your reply, its not a homework question i'm in the process of designing a SSRS report and i need this section in the store procedure in order to filter the data been trying to figure it out for ages.

    Question I'm assuming you would need to include a convert @set = date to remove the time??

    __________________________________________________________________________________
    Steve J
    Jnr Developer
    BSc(Hon)

  • Like so: -

    DECLARE @date DATETIME, @number INT

    SET @date = '2011-06-06 00:00:00'

    SET @number = 12

    ;WITH CTE AS (

    SELECT 0 AS months

    UNION ALL

    SELECT months + 1

    FROM CTE

    WHERE months < @number-1)

    SELECT DATEADD(MONTH,months,@date),

    CONVERT(VARCHAR(10),DATEADD(MONTH,months,@date), 101) AS mmddyyyy,

    CONVERT(VARCHAR(10),DATEADD(MONTH,months,@date), 103) AS ddmmyyyy,

    CONVERT(VARCHAR(12),DATEADD(MONTH,months,@date), 107) AS MMMddyyyy,

    CONVERT(VARCHAR(12),DATEADD(MONTH,months,@date), 113) AS ddMMMyyyy

    FROM CTE


    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/

  • Brilliant i can work with that

    __________________________________________________________________________________
    Steve J
    Jnr Developer
    BSc(Hon)

  • Jnrstevej (6/2/2011)


    Hi skcadavre,

    Thanks for your reply, its not a homework question i'm in the process of designing a SSRS report and i need this section in the store procedure in order to filter the data been trying to figure it out for ages.

    Question I'm assuming you would need to include a convert @set = date to remove the time??

    Since you are using SSRS, you should use the formatting available within SSRS to format the datetime field the way you want it.

    If you want to eliminate the time for filtering purposes (before it gets to SSRS), using CONVERT() is one of the worst possible ways to approach it. You should use the date/time functions to manipulate date/time data. Specifically, the following two expressions will give you midnight today and midnight on the first of the current month.

    SELECT

    Cast(Datediff(Day, 0, GetDate()) as datetime) AS MidnightToday

    , DateAdd(Month, DateDiff(Month, 0, GetDate()), 0) AS FirstOfCurrentMonth -- at midnight

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • drew.allen (6/2/2011)


    Jnrstevej (6/2/2011)


    Hi skcadavre,

    Thanks for your reply, its not a homework question i'm in the process of designing a SSRS report and i need this section in the store procedure in order to filter the data been trying to figure it out for ages.

    Question I'm assuming you would need to include a convert @set = date to remove the time??

    Since you are using SSRS, you should use the formatting available within SSRS to format the datetime field the way you want it.

    I agree with using SSRS formatting. Any data formatting is a presentation layer task, so I never like to do it in DB.

    drew.allen (6/2/2011)


    If you want to eliminate the time for filtering purposes (before it gets to SSRS), using CONVERT() is one of the worst possible ways to approach it. You should use the date/time functions to manipulate date/time data. Specifically, the following two expressions will give you midnight today and midnight on the first of the current month.

    SELECT

    Cast(Datediff(Day, 0, GetDate()) as datetime) AS MidnightToday

    , DateAdd(Month, DateDiff(Month, 0, GetDate()), 0) AS FirstOfCurrentMonth -- at midnight

    Drew

    When you post sweeping comments, you should probably include a test script that proves what you're claiming. Note, I'm not saying you're wrong. As I said before, I use the presentation layer when formatting data so I've never really done any formatting on large data sets, but your sweeping comment without any evidence doesn't change the opinions of anyone.


    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/

  • skcadavre (6/3/2011)


    When you post sweeping comments, you should probably include a test script that proves what you're claiming. Note, I'm not saying you're wrong. As I said before, I use the presentation layer when formatting data so I've never really done any formatting on large data sets, but your sweeping comment without any evidence doesn't change the opinions of anyone.

    I'm not getting paid to post here. I don't feel the need to post test scripts for something that is documented elsewhere and widely known, but if you want to pay me to do so, I will gladly post the requested scripts.

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • skcadavre (6/3/2011)


    When you post sweeping comments, you should probably include a test script that proves what you're claiming. {snip}... but your sweeping comment without any evidence doesn't change the opinions of anyone.

    Ah... ya got me between a rock and a hard spot here. 😉 I've dedicated a huge amount of time to dispelling SQL myths on the internet, especially when someone claims performance, so I'm right there with you when it comes to any claims of performance. I like to see people prove such statements.

    However... not only has it been proven that conversion of dates to VARCHARs is comparatively dreadfully slow, but the method that Drew used is one of the faster methods there is and it will absolutely blow the doors off of any conversion to a VARCHAR using CONVERT. So I can understand why he's reluctant to spend any additional time on what has become well known previously proven fact.

    That not withstanding, I'll be happy to prove it because it's a question asked so often that I got tired of writing ad hoc code for it and built a canned example. Drew's method is called DATEDIFF/DATETIME in the following code. Compare it to any of the conversions to VARCHAR and see why he was a bit adamant about it.

    /**********************************************************************************************************************

    Purpose:

    Create a voluminous test table with highly randomized DATETIME data.

    --Jeff Moden

    **********************************************************************************************************************/

    --===== Do this test in a nice safe place that everyone has.

    USE TempDB

    ;

    --===== Conditionally drop the test table to make reruns easier

    IF OBJECT_ID('dbo.JBMTest','U') IS NOT NULL

    DROP TABLE dbo.JBMTest

    ;

    --===== Create and populate a 1,000,000 row test table.

    -- "SomeID" has a range of 1 to 1,000,000 unique numbers

    -- "SomeDateTimeTime" has a range of >=01/01/2000 and <01/01/2020 non-unique date/times

    SELECT TOP 1000000

    SomeID = IDENTITY(INT,1,1),

    SomeDateTime = RAND(CHECKSUM(NEWID())) * DATEDIFF(dd,'2000','2020') + CAST('2000' AS DATETIME)

    INTO dbo.JBMTest

    FROM sys.all_columns ac1

    CROSS JOIN sys.all_columns ac2

    ;

    --===== This will take the display out of the picture so we

    -- can measure the true processing time in memory.

    DECLARE @BitBucketDATETIME DATETIME

    PRINT '========== BASELINE =========='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = SomeDateTime

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '========== DATEADD/DATEDIFF 1 =========='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = DATEADD(d, 0, DATEDIFF(d, 0, SomeDateTime))

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '========== DATEADD/DATEDIFF 2 =========='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = DATEADD(dd,DATEDIFF(dd,0,SomeDateTime),0)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '========== DATEDIFF Implicit =========='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = DATEDIFF(d, 0, SomeDateTime)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '========== DATEDIFF/DATETIME =========='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = CAST(DATEDIFF(d, 0, SomeDateTime) AS DATETIME)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '========== CONVERT =========='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = CONVERT(DATETIME,CONVERT(VARCHAR,SomeDateTime,100))

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '========== CONVERT Implicit=========='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = CONVERT(VARCHAR,SomeDateTime,100)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '===== FLOOR ====='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = CAST(FLOOR(CONVERT(FLOAT, SomeDateTime)) AS DATETIME)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '===== FLOOR Implicit ====='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = FLOOR(CONVERT(FLOAT, SomeDateTime))

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '===== ROUNDING 1 ====='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = CAST(CAST(SomeDateTime - 0.50000004 AS INT) AS DATETIME)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '===== ROUNDING 1 Implicit ====='

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = CAST(SomeDateTime - 0.50000004 AS INT)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '===== ROUNDING 2 ======'

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = CAST(ROUND(CAST(SomeDateTime AS FLOAT),0,1) AS DATETIME)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    PRINT '===== ROUNDING 2 Implicit ======'

    SET STATISTICS TIME ON

    SELECT @BitBucketDATETIME = ROUND(CAST(SomeDateTime AS FLOAT),0,1)

    FROM dbo.JBMTest WITH (NOLOCK)

    SET STATISTICS TIME OFF

    PRINT REPLICATE('=',80)

    For those that may have an interest, here's the output created by my 9 year old, single 1.8 GHz P4 CPU with 1GB of ram running Windows XP (sp3) and SQL Server 2005 (sp3).

    (1000000 row(s) affected)

    ========== BASELINE ==========

    SQL Server Execution Times:

    CPU time = 640 ms, elapsed time = 668 ms.

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

    ========== DATEADD/DATEDIFF 1 ==========

    SQL Server Execution Times:

    CPU time = 984 ms, elapsed time = 1026 ms.

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

    ========== DATEADD/DATEDIFF 2 ==========

    SQL Server Execution Times:

    CPU time = 797 ms, elapsed time = 810 ms.

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

    ========== DATEDIFF Implicit ==========

    SQL Server Execution Times:

    CPU time = 719 ms, elapsed time = 715 ms.

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

    ========== DATEDIFF/DATETIME ==========

    SQL Server Execution Times:

    CPU time = 734 ms, elapsed time = 737 ms.

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

    ========== CONVERT ==========

    SQL Server Execution Times:

    CPU time = 5500 ms, elapsed time = 5515 ms.

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

    ========== CONVERT Implicit==========

    SQL Server Execution Times:

    CPU time = 5375 ms, elapsed time = 5389 ms.

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

    ===== FLOOR =====

    SQL Server Execution Times:

    CPU time = 1016 ms, elapsed time = 1018 ms.

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

    ===== FLOOR Implicit =====

    SQL Server Execution Times:

    CPU time = 969 ms, elapsed time = 970 ms.

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

    ===== ROUNDING 1 =====

    SQL Server Execution Times:

    CPU time = 718 ms, elapsed time = 720 ms.

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

    ===== ROUNDING 1 Implicit =====

    SQL Server Execution Times:

    CPU time = 719 ms, elapsed time = 718 ms.

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

    ===== ROUNDING 2 ======

    SQL Server Execution Times:

    CPU time = 1453 ms, elapsed time = 1465 ms.

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

    ===== ROUNDING 2 Implicit ======

    SQL Server Execution Times:

    CPU time = 1532 ms, elapsed time = 1566 ms.

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

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • As a bit of a sidebar, here's a blanket statement...

    [font="Arial Black"]NEVER EVER USE A RECURSIVE CTE TO BUILD SEQUENTIAL SETS OF NUMBERS NO MATTER HOW SMALL THE SET MAY BE!!! [/font]:-P

    Here's the proof... I created some code to test and measure several simple counting methods including that of the Recursive CTE's. To make a very long story short, here're the performance curves measured to the nearest millisecond for counts of 1 to 100...

    Whoa! Wait a minute! I see that the fat red line is the Recursive CTE performance curve but where are the performance curves for the rest of the sequential counter methods? Well, take a look way down in the right hand corner of the chart. See the almost imperceptible rise of color above the "Zero" line? That's the beginning of the linear trendline of all of the rest of them. I had to use the trendline just to get them to show up on this chart because they were all flat 0 milliseconds (again, rounded to the nearest millisecond).

    You'll have to trust me for a bit... I'm not going to post the code or the other charts here because this problem of people using Recursive CTE's to generate simple numeric sequences has become so rampant that I'm writing an article on it. 😀

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jnrstevej (6/2/2011)


    Brilliant i can work with that

    My recommendation is that you don't so that you don't get into any bad habits. If you have one, format the dates in the report generator (or Excel). Either way, replace that Recursive CTE with a Tally Table ( http://www.sqlservercentral.com/articles/T-SQL/62867/ ) or other suitable method.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff Moden (6/3/2011)


    You'll have to trust me for a bit... I'm not going to post the code or the other charts here because this problem of people using Recursive CTE's to generate simple numeric sequences has become so rampant that I'm writing an article on it. 😀

    Not trusting Jeff when he posts tested statistics is like not trusting Socrates(sp?) when he discusssed logical proofing. It's just silly.

    If Jeff is willing to put his name on the line, something he considers quite valuable, to prove a point with numbers... it's worth listening to.


    - Craig Farrell

    Never stop learning, even if it hurts. Ego bruises are practically mandatory as you learn unless you've never risked enough to make a mistake.

    For better assistance in answering your questions[/url] | Forum Netiquette
    For index/tuning help, follow these directions.[/url] |Tally Tables[/url]

    Twitter: @AnyWayDBA

  • Thanks for the endorsement, Craig. :blush: Yeah... this one is bad and it's getting out of hand. I see more and more people using recursive CTEs to generate sequences of numbers and they just don't understand how something without an explicit loop and something that MS advertises as a feature can be so bad.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • drew.allen (6/3/2011)


    skcadavre (6/3/2011)


    When you post sweeping comments, you should probably include a test script that proves what you're claiming. Note, I'm not saying you're wrong. As I said before, I use the presentation layer when formatting data so I've never really done any formatting on large data sets, but your sweeping comment without any evidence doesn't change the opinions of anyone.

    I'm not getting paid to post here. I don't feel the need to post test scripts for something that is documented elsewhere and widely known, but if you want to pay me to do so, I will gladly post the requested scripts.

    Drew

    *shrugs* A link would've been enough 😉

    Jeff Moden (6/3/2011)


    skcadavre (6/3/2011)


    When you post sweeping comments, you should probably include a test script that proves what you're claiming. {snip}... but your sweeping comment without any evidence doesn't change the opinions of anyone.

    However... not only has it been proven that conversion of dates to VARCHARs is comparatively dreadfully slow, but the method that Drew used is one of the faster methods there is and it will absolutely blow the doors off of any conversion to a VARCHAR using CONVERT. So I can understand why he's reluctant to spend any additional time on what has become well known previously proven fact.

    Awesome. I'm glad I've always pushed this sort of task into the presentation layer 🙂

    Jeff Moden (6/3/2011)


    You'll have to trust me for a bit... I'm not going to post the code or the other charts here because this problem of people using Recursive CTE's to generate simple numeric sequences has become so rampant that I'm writing an article on it. 😀

    I look forward to it. Generally I'd use a tally table when I need a list of numbers, although I am guilty of using recursive CTEs when the list size is small enough.


    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/

  • skcadavre (6/4/2011)


    although I am guilty of using recursive CTEs when the list size is small enough.

    I guess that's the point I'm trying to make. The list is never small enough. 🙂 I know you personally know not to use such a thing to build larger lists but I'm concerned (especially since lot's of people have started to use rCTE's for lists) that those who don't know about the problems with rCTE's will see that the code works and use it for something else where the performance will absolutely crush any notion of scalability in their code.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

Viewing 15 posts - 1 through 15 (of 24 total)

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