Need to find Saturday # between two dates

  • Hi Everyone,

    I don't know how to edit my Topic title since it's a little misleading.

    I'm trying to find if the Saturdays worked in Bi-Weekly period is first or second, based on the Saturday occurrence the CODEID column value changes from 01 to another #, for example if it's first Saturday then CODEID changes from 01 to 02 and it's second Saturday then the CODEID changes from 01 to 03.

    Below is my table, current result and desired results.

    Thank you...

    My Table:

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    SELECT * FROM SampleData

    Current Results

    PERSONHOURSRATECODEIDDOW DATE

    12347.0040.0001Thursday05/01/2014

    12348.0040.0001Friday 05/02/2014

    12343.5040.0001Saturday05/03/2014

    12343.5040.0001Monday 05/05/2014

    12348.0040.0001Tuesday 05/06/2014

    12343.5040.0001Wednesday05/07/2014

    12343.5040.0001Thursday05/08/2014

    12347.0040.0001Friday 05/09/2014

    12343.0040.0001Saturday05/10/2014

    Expected Results

    PERSONHOURSRATECODEIDDOW DATE

    12347.0040.0001Thursday05/01/2014

    12348.0040.0001Friday 05/02/2014

    12343.5040.0002Saturday05/03/2014

    12343.5040.0001Monday 05/05/2014

    12348.0040.0001Tuesday 05/06/2014

    12343.5040.0001Wednesday05/07/2014

    12343.5040.0001Thursday05/08/2014

    12347.0040.0001Friday 05/09/2014

    12343.0040.0003Saturday05/10/2014

  • I think I just very carefully solved this using a 2012 solution... figured I would post it for people to tear apart...

    the ROWS PRECEDING window function is new in 2012... sorry!

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    SELECT Person

    , [Hours]

    , Rate

    , DOW

    , [Date]

    --, SatCount

    , CodeID = '0' + CAST(1 + CASE WHEN DOW='Saturday' THEN

    SUM([SatCount]) OVER (PARTITION BY Person

    ORDER BY [Date]

    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

    ELSE 0 END AS CHAR(2))

    FROM

    (SELECT Person

    , [Hours]

    , Rate

    , CodeID

    , DOW

    , [Date]

    , SatCount = CASE WHEN DOW='Saturday' THEN 1 ELSE 0 END

    FROM SampleData) x

  • Hi There,

    Oh man, I wish this client had SQL Server 2012, they are using SQL 2005 🙁

    Thanks for the help though 🙂

    Take care,

  • pietlinden (6/17/2014)


    I think I just very carefully solved this using a 2012 solution... figured I would post it for people to tear apart...

    the ROWS PRECEDING window function is new in 2012... sorry!

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    SELECT Person

    , [Hours]

    , Rate

    , DOW

    , [Date]

    --, SatCount

    , CodeID = '0' + CAST(1 + CASE WHEN DOW='Saturday' THEN

    SUM([SatCount]) OVER (PARTITION BY Person

    ORDER BY [Date]

    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

    ELSE 0 END AS CHAR(2))

    FROM

    (SELECT Person

    , [Hours]

    , Rate

    , CodeID

    , DOW

    , [Date]

    , SatCount = CASE WHEN DOW='Saturday' THEN 1 ELSE 0 END

    FROM SampleData) x

    Not bad;-) the only flaw is the absence of the correct set divisor, the partition must include the CODEID.

    (edit) I may have jumped the gun here with the CODEID:w00t:

    😎

  • Two solutions, first one for 2005 and later, the second 2012 and later. The difference is that the first one uses self-joining which makes it less efficient. For very large sets on earlier versions, I would suggest looking at quirky updates[/url].

    😎

    Solution for 2005 and later.

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    /* 2005 AND LATER */

    SELECT

    SD.PERSON

    ,SD.HOURS

    ,SD.RATE

    ,SD.CODEID+ ISNULL(SAD.SAT_COUNT,0) AS CODEID

    ,SD.DOW

    ,SD.DATE

    FROM SampleData SD

    LEFT OUTER JOIN

    (

    SELECT

    ROW_NUMBER() OVER

    (

    PARTITION BY SD.PERSON

    ,SD.CODEID

    ORDER BY SD.DATE

    ) SAT_COUNT

    ,SD.PERSON

    ,SD.CODEID

    ,SD.DATE

    FROM SampleData SD

    WHERE SD.DOW = 'Saturday'

    ) AS SAD

    ON SD.DATE = SAD.DATE

    AND SD.PERSON = SAD.PERSON

    AND SD.CODEID = SAD.CODEID

    Solution for 2012 and later

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    /* 2012 AND LATER */

    SELECT

    SD.PERSON

    ,SD.HOURS

    ,SD.RATE

    ,SD.CODEID +

    CASE

    WHEN SD.DOW = 'Saturday' THEN

    SUM(CASE

    WHEN SD.DOW = 'Saturday' THEN 1

    ELSE 0

    END) OVER

    (

    PARTITION BY SD.PERSON

    ,SD.CODEID

    ORDER BY SD.DATE

    ROWS BETWEEN UNBOUNDED PRECEDING

    AND CURRENT ROW

    )

    ELSE 0

    END AS CODEID

    ,SD.DOW

    ,SD.DATE

    FROM SampleData SD;

    Results

    PERSON HOURS RATE CODEID DOW DATE

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

    1234 7.00 40.00 1 Thursday 05/01/2014

    1234 8.00 40.00 1 Friday 05/02/2014

    1234 3.50 40.00 2 Saturday 05/03/2014

    1234 3.50 40.00 1 Monday 05/05/2014

    1234 8.00 40.00 1 Tuesday 05/06/2014

    1234 3.50 40.00 1 Wednesday 05/07/2014

    1234 3.50 40.00 1 Thursday 05/08/2014

    1234 7.00 40.00 1 Friday 05/09/2014

    1234 3.00 40.00 3 Saturday 05/10/2014

  • Eirikur Eiriksson (6/17/2014)


    Two solutions, first one for 2005 and later, the second 2012 and later. The difference is that the first one uses self-joining which makes it less efficient. For very large sets on earlier versions, I would suggest looking at quirky updates[/url].

    You do not really need to use self-join here even for SQL2005, this will be good enough:

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    SELECT

    SD.PERSON

    ,SD.HOURS

    ,SD.RATE

    ,CASE WHEN SD.DOW != 'Saturday' THEN 1

    ELSE ROW_NUMBER() OVER

    (

    PARTITION BY SD.PERSON

    ,SD.CODEID

    ,CASE WHEN SD.DOW = 'Saturday' THEN SD.DOW ELSE 'WD' END

    ORDER BY SD.DATE

    ) + 1

    END AS SAT_COUNT

    ,SD.DOW

    ,SD.DATE

    FROM SampleData SD

    ORDER BY SD.PERSON

    ,SD.CODEID

    ,SD.DATE

    _____________________________________________
    "The only true wisdom is in knowing you know nothing"
    "O skol'ko nam otkrytiy chudnyh prevnosit microsofta duh!":-D
    (So many miracle inventions provided by MS to us...)

    How to post your question to get the best and quick help[/url]

  • Awesome, this is perfect.

    Thank you very much everyone for all the help 🙂

  • Are you just trying to determine the relative Saturday# within the month? If so, there are methods with vastly less difficulty and overhead.

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • Hi There,

    Actually the client changed the requirements, if it's the first Saturday between the selected dates then in CODEID column we would have a value of 450, for the second Saturday value would be 651. If the first Saturday was not worked then still the second Saturday should have a value of 451.

    I'm not sure if it's doable to being with so that's why I didn't post anything back until you asked me 🙂

    Example # 1, when both Saturdays are worked.

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    SELECT * FROM SampleData

    Current Results

    PERSONHOURSRATECODEIDDOW DATE

    12347.0040.0001Thursday05/01/2014

    12348.0040.0001Friday 05/02/2014

    12343.5040.0001Saturday05/03/2014

    12343.5040.0001Monday 05/05/2014

    12348.0040.0001Tuesday 05/06/2014

    12343.5040.0001Wednesday05/07/2014

    12343.5040.0001Thursday05/08/2014

    12347.0040.0001Friday 05/09/2014

    12343.0040.0001Saturday05/10/2014

    Desired Results

    PERSONHOURSRATECODEIDDOW DATE

    12347.0040.0001Thursday05/01/2014

    12348.0040.0001Friday 05/02/2014

    12343.5040.00450Saturday05/03/2014

    12343.5040.0001Monday 05/05/2014

    12348.0040.0001Tuesday 05/06/2014

    12343.5040.0001Wednesday05/07/2014

    12343.5040.0001Thursday05/08/2014

    12347.0040.0001Friday 05/09/2014

    12343.0040.00451Saturday05/10/2014

    Example #2, when 1st Saturday is worked but not 2nd Saturday.

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    )

    SELECT * FROM SampleData

    Current Results

    PERSONHOURSRATECODEIDDOW DATE

    12347.0040.0001Thursday05/01/2014

    12348.0040.0001Friday 05/02/2014

    12343.5040.0001Saturday05/03/2014

    12343.5040.0001Monday 05/05/2014

    12348.0040.0001Tuesday 05/06/2014

    12343.5040.0001Wednesday05/07/2014

    12343.5040.0001Thursday05/08/2014

    12347.0040.0001Friday 05/09/2014

    Desired Results

    PERSONHOURSRATECODEIDDOW DATE

    12347.0040.0001Thursday05/01/2014

    12348.0040.0001Friday 05/02/2014

    12343.5040.00450Saturday05/03/2014

    12343.5040.0001Monday 05/05/2014

    12348.0040.0001Tuesday 05/06/2014

    12343.5040.0001Wednesday05/07/2014

    12343.5040.0001Thursday05/08/2014

    12347.0040.0001Friday 05/09/2014

    Example #3, when 1st Saturday is not worked but the 2nd Saturday is.

    WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    SELECT * FROM SampleData

    Current Results

    PERSONHOURSRATECODEIDDOW DATE

    12347.0040.0001Thursday05/01/2014

    12348.0040.0001Friday 05/02/2014

    12343.5040.0001Monday 05/05/2014

    12348.0040.0001Tuesday 05/06/2014

    12343.5040.0001Wednesday05/07/2014

    12343.5040.0001Thursday05/08/2014

    12347.0040.0001Friday 05/09/2014

    12343.0040.0001Saturday05/10/2014

    Desired Results

    PERSONHOURSRATECODEIDDOW DATE

    12347.0040.0001Thursday05/01/2014

    12348.0040.0001Friday 05/02/2014

    12343.5040.0001Monday 05/05/2014

    12348.0040.0001Tuesday 05/06/2014

    12343.5040.0001Wednesday05/07/2014

    12343.5040.0001Thursday05/08/2014

    12347.0040.0001Friday 05/09/2014

    12343.0040.00451Saturday05/10/2014

    Thank you,

  • Here is a quick solution using a CALENDAR CTE

    😎

    USE tempdb;

    GO

    ;WITH SampleData (PERSON,[HOURS],[RATE],[CODEID],[DOW],[DATE]) AS

    (

    SELECT 1234,7.00,40.00,01,'Thursday','05/01/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Friday','05/02/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Saturday','05/03/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Monday','05/05/2014'

    UNION ALL SELECT 1234,8.0,40.0,01,'Tuesday','05/06/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Wednesday','05/07/2014'

    UNION ALL SELECT 1234,3.5,40.0,01,'Thursday','05/08/2014'

    UNION ALL SELECT 1234,7.0,40.0,01,'Friday','05/09/2014'

    UNION ALL SELECT 1234,3.0,40.0,01,'Saturday','05/10/2014'

    )

    ,DATE_RANGE AS

    (

    SELECT

    MIN(SD.DATE) AS START_DATE

    ,DATEDIFF(DAY,MIN(SD.DATE),MAX(SD.DATE)) + 1 AS DATE_COUNT

    FROM SampleData SD

    )

    ,TN(N) AS (SELECT N FROM (VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,CALENDAR AS

    (

    SELECT

    ROW_NUMBER() OVER (ORDER BY DR.START_DATE) + 449 AS CODEID

    ,CAST(DATEADD(DAY,NM.N,DR.START_DATE) AS DATE) AS SATUR_DAY

    FROM DATE_RANGE DR

    OUTER APPLY

    (SELECT TOP (DR.DATE_COUNT) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 FROM TN T1,TN T2,TN T3) NM(N)

    WHERE DATENAME(WEEKDAY,DATEADD(DAY,NM.N,DR.START_DATE)) = N'Saturday'

    )

    SELECT

    SD.PERSON

    ,SD.HOURS

    ,SD.RATE

    ,ISNULL(CA.CODEID,SD.CODEID) AS CODEID

    ,SD.DOW

    ,SD.DATE

    FROM SampleData SD

    LEFT OUTER JOIN CALENDAR CA

    ON SD.DATE = CA.SATUR_DAY;

    Results

    PERSON HOURS RATE CODEID DOW DATE

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

    1234 7.00 40.00 1 Thursday 05/01/2014

    1234 8.00 40.00 1 Friday 05/02/2014

    1234 3.50 40.00 450 Saturday 05/03/2014

    1234 3.50 40.00 1 Monday 05/05/2014

    1234 8.00 40.00 1 Tuesday 05/06/2014

    1234 3.50 40.00 1 Wednesday 05/07/2014

    1234 3.50 40.00 1 Thursday 05/08/2014

    1234 7.00 40.00 1 Friday 05/09/2014

    1234 3.00 40.00 451 Saturday 05/10/2014

  • Yep, works like a charm 🙂

    Thank you very much Sir !!

Viewing 11 posts - 1 through 10 (of 10 total)

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