Query to split difference (number of nights) between 2 dates into respective "Month" column

  • Hi all,

    I'm using SQL Server 2012 and I need to run a query against my database that will output the difference between 2 dates (namely, DateOfArrival and DateOfDeparture) into the correct month column in the output.

    Both DateOfArrival and DateOfDeparture are in the same table (let's say GuestStay). I will also need some other fields from this table and do some joins on some other tables but I will simplify things so as to solve my main problem here. Let's say the fields needed from the GuestStay table looks like below:

    I need my query to output in the following format:

    Can anyone please help how to write this query?

  • I can't see your images because dropbox is blocked at work. That's why we usually ask for DDL, sample data and expected results as a runnable script. If you can post it, that would be great.

    Meanwhile, what's wrong with using DATEDIFF()?

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Try this for a size

    😎

    USE tempdb;

    GO

    SET NOCOUNT ON;

    ;WITH SAMPLE_DATA ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    ,MONTH_NUMBERS AS (SELECT MNO FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS X(MNO))

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM SAMPLE_DATA SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture;

    Results

    ID number DateOfArrival DateOfDeparture JAN14 FEB14 MAR14 APR14 MAY14 JUN14 JUL14 AUG14 SEP14 OCT14 NOV14 DEC14

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

    1056 2014-04-29 2014-05-03 0 0 0 1 3 0 0 0 0 0 0 0

    2031 2014-03-20 2014-03-26 0 0 6 0 0 0 0 0 0 0 0 0

    3245 2014-06-19 2014-06-20 0 0 0 0 0 1 0 0 0 0 0 0

  • Thanks a lot, Eirikur Eiriksson! Wow! I wished I could write SQL queries that good!

    I'm a bit confused with the first part of the query (blame that on my lack of knowledge of SQL queries). If I understand well, you have created only 2 tables to tackle the problem: Sample_data and Counting_days? Sample_data is the equivalent of my GuestStay table?

    Can you please replace the terms used in the query with my table name GuestStay. I'll go from there! Thanks again!

  • Here is the same code with the changed name and some explanatory comments. I noticed I had left the month sequence in the other code without using it, no need for that so I removed it.

    😎

    USE tempdb;

    GO

    SET NOCOUNT ON;

    /* The sample data for Guest Stay, you can replace this

    with your table, the likely equivalent would be for the

    year 2014

    ;WITH GuestStay AS

    (

    SELECT

    [ID number]

    ,DateOfArrival

    ,DateOfDeparture

    FROM [myTableName]

    WHERE YEAR(DateOfArrival) = 2014

    )

    */

    ;WITH GuestStay ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    /* A tally table seed for the numbers table used to count

    all days in the stay, that is to unpack the period. The

    NULL values are meant to underline that the actual values

    are not relevant, only that there are 10 empty/blank/meaningless

    rows in this set.

    */

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    /* The unpacking of the period (event interval, events being

    start and end of stay

    */

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    /* Window function Count, think of the partition as

    for every row in the set that belongs to the partition

    combination, count the entries, or in other terms, devide

    the set by those columns and count the entries

    */

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM GuestStay SD

    /* This is the driver for the unpacking, generates a sequence

    of numbers matching the number of days between the two dates

    for each record/row

    */

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    /* Crosstab to "columize" the output. The MAX simply puts any value greater than

    zero in the column if it exists

    */

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    /* Each line represents one column, when the MONTH_NO matches it returns

    the count of nights (COUNT_IN_MONTH) for that month, otherwise zero

    */

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture;

  • Eirikur Eiriksson (9/23/2014)


    Try this for a size

    😎

    USE tempdb;

    GO

    SET NOCOUNT ON;

    ;WITH SAMPLE_DATA ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    ,MONTH_NUMBERS AS (SELECT MNO FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS X(MNO))

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM SAMPLE_DATA SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture;

    Results

    ID number DateOfArrival DateOfDeparture JAN14 FEB14 MAR14 APR14 MAY14 JUN14 JUL14 AUG14 SEP14 OCT14 NOV14 DEC14

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

    1056 2014-04-29 2014-05-03 0 0 0 1 3 0 0 0 0 0 0 0

    2031 2014-03-20 2014-03-26 0 0 6 0 0 0 0 0 0 0 0 0

    3245 2014-06-19 2014-06-20 0 0 0 0 0 1 0 0 0 0 0 0

    Sorry, have to rant, and this is nothing to do with what Eirikur's code does, just the fact that the CTE is started with an unnecessary semicolon. It is something I see many people doing in their code. This is why I totally dislike the sample code in BOL regarding CTE's. A semicolon is NOT required at the beginning of a CTE (WITH clause). Semicolons are statement terminators, not statement begininators. Looking at the code Eirikur wrote take a close look at the CTE:

    USE tempdb;

    GO

    SET NOCOUNT ON; -- <<Here, we have a semicolon properly used as a statement terminator

    -- Followed directly below by another semicolon that is not needed because of the terminator above.

    ;WITH SAMPLE_DATA ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    ,MONTH_NUMBERS AS (SELECT MNO FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS X(MNO))

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM SAMPLE_DATA SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture; -- << Not only that, but the code using the CTE is also terminated by a semicolon.

    If you read BOL and the information regarding CTEs, it clearly states that for a CTE the PREVIOUS statement must be terminated by a semicolon. The practice of starting a CTE with a semicolon to ensure that the previous statement is terminated by a semicolon, imho, teaches the wrong way to code.

    .It is like writing sentences like this .Putting the punction at the start of each sentence to ensure that the previous sentence is properly terminated

    .Does this actually make any sense ?Personally, it doesn't.

  • Eirikur Eiriksson (9/23/2014)


    Here is the same code with the changed name and some explanatory comments. I noticed I had left the month sequence in the other code without using it, no need for that so I removed it.

    😎

    USE tempdb;

    GO

    SET NOCOUNT ON;

    /* The sample data for Guest Stay, you can replace this

    with your table, the likely equivalent would be for the

    year 2014

    ;WITH GuestStay AS

    (

    SELECT

    [ID number]

    ,DateOfArrival

    ,DateOfDeparture

    FROM [myTableName]

    WHERE YEAR(DateOfArrival) = 2014

    )

    */

    ;WITH GuestStay ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    /* A tally table seed for the numbers table used to count

    all days in the stay, that is to unpack the period. The

    NULL values are meant to underline that the actual values

    are not relevant, only that there are 10 empty/blank/meaningless

    rows in this set.

    */

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    /* The unpacking of the period (event interval, events being

    start and end of stay

    */

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    /* Window function Count, think of the partition as

    for every row in the set that belongs to the partition

    combination, count the entries, or in other terms, devide

    the set by those columns and count the entries

    */

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM GuestStay SD

    /* This is the driver for the unpacking, generates a sequence

    of numbers matching the number of days between the two dates

    for each record/row

    */

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    /* Crosstab to "columize" the output. The MAX simply puts any value greater than

    zero in the column if it exists

    */

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    /* Each line represents one column, when the MONTH_NO matches it returns

    the count of nights (COUNT_IN_MONTH) for that month, otherwise zero

    */

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture;

    Thanks again Eirukur for your efforts and time! Highly appreciated! This part of the code is posing me some problems:

    ;WITH GuestStay ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    Here, you have explicitly listed the Id Number, DateOf Arrival and DateOfDeparture. In my GuestStay table, these amount to more than 1,000 of rows! How do I deal with this?

  • Thanks again Eirukur for your efforts and time! Highly appreciated! This part of the code is posing me some problems:

    ;WITH GuestStay ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    Here, you have explicitly listed the Id Number, DateOf Arrival and DateOfDeparture. In my GuestStay table, these amount to more than 1,000 of rows! How do I deal with this?

    I am trying to explain this in the code's comments, maybe not being clear enough so lets try again.

    The Common Table Expression with the VALUES construct is there as I do not have your data. It is used in the example as a substitute for your data and should of course be removed and replaced with a select statement targeting your table. I know this can be slightly confusing at first;-)

    I gave an example of the select statement in the comment but it is again a pseudo coded demonstration.

    Hope this helps

    😎

    /* The sample data for Guest Stay, you can replace this

    with your table, the likely equivalent would be for the

    year 2014

    ;WITH GuestStay AS

    (

    SELECT

    [ID number]

    ,DateOfArrival

    ,DateOfDeparture

    FROM [myTableName]

    WHERE YEAR(DateOfArrival) = 2014 --<--demonstration purpose only!

    )

    */

    ;WITH GuestStay ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

  • Thanks, Eirikur! Got it now! I should have read more attentively! Thanks again! πŸ™‚

  • Lynn Pettis (9/23/2014)


    Eirikur Eiriksson (9/23/2014)


    Try this for a size

    😎

    USE tempdb;

    GO

    SET NOCOUNT ON;

    ;WITH SAMPLE_DATA ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    ,MONTH_NUMBERS AS (SELECT MNO FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS X(MNO))

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM SAMPLE_DATA SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture;

    Results

    ID number DateOfArrival DateOfDeparture JAN14 FEB14 MAR14 APR14 MAY14 JUN14 JUL14 AUG14 SEP14 OCT14 NOV14 DEC14

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

    1056 2014-04-29 2014-05-03 0 0 0 1 3 0 0 0 0 0 0 0

    2031 2014-03-20 2014-03-26 0 0 6 0 0 0 0 0 0 0 0 0

    3245 2014-06-19 2014-06-20 0 0 0 0 0 1 0 0 0 0 0 0

    Sorry, have to rant, and this is nothing to do with what Eirikur's code does, just the fact that the CTE is started with an unnecessary semicolon. It is something I see many people doing in their code. This is why I totally dislike the sample code in BOL regarding CTE's. A semicolon is NOT required at the beginning of a CTE (WITH clause). Semicolons are statement terminators, not statement begininators. Looking at the code Eirikur wrote take a close look at the CTE:

    USE tempdb;

    GO

    SET NOCOUNT ON; -- <<Here, we have a semicolon properly used as a statement terminator

    -- Followed directly below by another semicolon that is not needed because of the terminator above.

    ;WITH SAMPLE_DATA ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    ,MONTH_NUMBERS AS (SELECT MNO FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS X(MNO))

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM SAMPLE_DATA SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture; -- << Not only that, but the code using the CTE is also terminated by a semicolon.

    If you read BOL and the information regarding CTEs, it clearly states that for a CTE the PREVIOUS statement must be terminated by a semicolon. The practice of starting a CTE with a semicolon to ensure that the previous statement is terminated by a semicolon, imho, teaches the wrong way to code.

    .It is like writing sentences like this .Putting the punction at the start of each sentence to ensure that the previous sentence is properly terminated

    .Does this actually make any sense ?Personally, it doesn't.

    Lynn, it's just a small effort to minimize the collateral damage of copypaste;-) Don't have to worry about where in the script it ends, it will work.;-)

    😎

  • Hi Eirukur,

    I'm afraid it's still not working for me. I'm sure I'm doing something wrong with the syntax! Grateful if you could have a look and point out the error.

    Here's your original codes:

    ;WITH GuestStay ([ID number],ArrivalDate,DepartureDate)

    AS SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],ArrivalDate,DepartureDate)

    And here's my modified codes:

    ;WITH GuestStay AS

    (

    SELECT

    [ID number],

    ArrivalDate,

    DepartureDate

    FROM GuestStay

    where YEAR(ArrivalDate) = 2014)

    ) AS X([ID number],ArrivalDate,DepartureDate)

    )

    I didn't modify anything in the remaining codes. Why isn't it working?

  • hoolash (9/26/2014)


    Hi Eirukur,

    I'm afraid it's still not working for me. I'm sure I'm doing something wrong with the syntax! Grateful if you could have a look and point out the error.

    Here's your original codes:

    ;WITH GuestStay ([ID number],ArrivalDate,DepartureDate)

    AS SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],ArrivalDate,DepartureDate)

    And here's my modified codes:

    ;WITH GuestStay AS

    (

    SELECT

    [ID number],

    ArrivalDate,

    DepartureDate

    FROM GuestStay

    where YEAR(ArrivalDate) = 2014)

    ) AS X([ID number],ArrivalDate,DepartureDate)

    )

    I didn't modify anything in the remaining codes. Why isn't it working?

    Can you tell us what the query is or isn't doing and if there's an error message, post it up? Also, please post the whole query that you are attempting to run. The section of the query which you've posted may not be the offending part - and probably isn't.

    β€œ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

  • Eirikur Eiriksson (9/24/2014)


    Lynn Pettis (9/23/2014)


    Eirikur Eiriksson (9/23/2014)


    Try this for a size

    😎

    USE tempdb;

    GO

    SET NOCOUNT ON;

    ;WITH SAMPLE_DATA ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    ,MONTH_NUMBERS AS (SELECT MNO FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS X(MNO))

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM SAMPLE_DATA SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture;

    Results

    ID number DateOfArrival DateOfDeparture JAN14 FEB14 MAR14 APR14 MAY14 JUN14 JUL14 AUG14 SEP14 OCT14 NOV14 DEC14

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

    1056 2014-04-29 2014-05-03 0 0 0 1 3 0 0 0 0 0 0 0

    2031 2014-03-20 2014-03-26 0 0 6 0 0 0 0 0 0 0 0 0

    3245 2014-06-19 2014-06-20 0 0 0 0 0 1 0 0 0 0 0 0

    Sorry, have to rant, and this is nothing to do with what Eirikur's code does, just the fact that the CTE is started with an unnecessary semicolon. It is something I see many people doing in their code. This is why I totally dislike the sample code in BOL regarding CTE's. A semicolon is NOT required at the beginning of a CTE (WITH clause). Semicolons are statement terminators, not statement begininators. Looking at the code Eirikur wrote take a close look at the CTE:

    USE tempdb;

    GO

    SET NOCOUNT ON; -- <<Here, we have a semicolon properly used as a statement terminator

    -- Followed directly below by another semicolon that is not needed because of the terminator above.

    ;WITH SAMPLE_DATA ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    ,MONTH_NUMBERS AS (SELECT MNO FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS X(MNO))

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM SAMPLE_DATA SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture; -- << Not only that, but the code using the CTE is also terminated by a semicolon.

    If you read BOL and the information regarding CTEs, it clearly states that for a CTE the PREVIOUS statement must be terminated by a semicolon. The practice of starting a CTE with a semicolon to ensure that the previous statement is terminated by a semicolon, imho, teaches the wrong way to code.

    .It is like writing sentences like this .Putting the punction at the start of each sentence to ensure that the previous sentence is properly terminated

    .Does this actually make any sense ?Personally, it doesn't.

    Lynn, it's just a small effort to minimize the collateral damage of copypaste;-) Don't have to worry about where in the script it ends, it will work.;-)

    😎

    It is a pet peeve. Semicolons do not belong at the beginning of a statement. You also have to realize I try to ensure that I terminate ALL statements with a semicolon. Doesn't mean I always succeed, but that is what I strive for in my code.

  • Hi ChrisM,

    Here is the full query:

    USE MYDATABASE;

    GO

    SET NOCOUNT ON;

    ;WITH GuestStay ([ReservationStayID],ArrivalDate,DepartureDate)

    AS

    (

    SELECT ReservationStayID,ArrivalDate,DepartureDate

    FROM GuestNameInfo

    WHERE YEAR(ArrivalDate)=2014) AS X([ReservationStayID],ArrivalDate,DepartureDate)

    )

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ReservationStayID]

    ,SD.ArrivalDate

    ,SD.DepartureDate

    ,MONTH(DATEADD(DAY,NM.N,SD.ArrivalDate)) AS MONTH_NO

    ,COUNT(SD.[ReservationStayID]) OVER

    (

    PARTITION BY SD.[ReservationStayID]

    ,MONTH(DATEADD(DAY,NM.N,SD.ArrivalDate))

    ) AS COUNT_IN_MONTH

    FROM GuestStay SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.ArrivalDate,SD.DepartureDate) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ReservationStayID]

    ,CD.ArrivalDate

    ,CD.DepartureDate

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ReservationStayID]

    ,CD.ArrivalDate

    ,CD.DepartureDate;

    And here is the error message:

    Msg 156, Level 15, State 1, Line 10

    Incorrect syntax near the keyword 'AS'.

    Msg 102, Level 15, State 1, Line 16

    Incorrect syntax near ','.

  • Eirikur Eiriksson (9/23/2014)


    Try this for a size

    😎

    USE tempdb;

    GO

    SET NOCOUNT ON;

    ;WITH SAMPLE_DATA ([ID number],DateOfArrival,DateOfDeparture)

    AS (SELECT * FROM (VALUES

    (2031,'2014-03-20','2014-03-26')

    ,(1056,'2014-04-29','2014-05-03')

    ,(3245,'2014-06-19','2014-06-20')

    ) AS X([ID number],DateOfArrival,DateOfDeparture)

    )

    ,MONTH_NUMBERS AS (SELECT MNO FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS X(MNO))

    ,T(N) AS (SELECT N FROM ( VALUES (NULL),(NULL),(NULL),

    (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))

    ,COUNTING_DAYS AS

    (

    SELECT

    SD.[ID number]

    ,SD.DateOfArrival

    ,SD.DateOfDeparture

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival)) AS MONTH_NO

    ,COUNT(SD.[ID number]) OVER

    (

    PARTITION BY SD.[ID number]

    ,MONTH(DATEADD(DAY,NM.N,SD.DateOfArrival))

    ) AS COUNT_IN_MONTH

    FROM SAMPLE_DATA SD

    OUTER APPLY (SELECT TOP(DATEDIFF(DAY,SD.DateOfArrival,SD.DateOfDeparture) ) ROW_NUMBER()

    OVER (ORDER BY (SELECT NULL)) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7) AS NM

    )

    SELECT

    CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture

    ,MAX(CASE WHEN CD.MONTH_NO = 1 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JAN14

    ,MAX(CASE WHEN CD.MONTH_NO = 2 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS FEB14

    ,MAX(CASE WHEN CD.MONTH_NO = 3 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAR14

    ,MAX(CASE WHEN CD.MONTH_NO = 4 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS APR14

    ,MAX(CASE WHEN CD.MONTH_NO = 5 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS MAY14

    ,MAX(CASE WHEN CD.MONTH_NO = 6 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUN14

    ,MAX(CASE WHEN CD.MONTH_NO = 7 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS JUL14

    ,MAX(CASE WHEN CD.MONTH_NO = 8 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS AUG14

    ,MAX(CASE WHEN CD.MONTH_NO = 9 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS SEP14

    ,MAX(CASE WHEN CD.MONTH_NO = 10 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS OCT14

    ,MAX(CASE WHEN CD.MONTH_NO = 11 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS NOV14

    ,MAX(CASE WHEN CD.MONTH_NO = 12 THEN CD.COUNT_IN_MONTH ELSE 0 END) AS DEC14

    FROM COUNTING_DAYS CD

    GROUP BY CD.[ID number]

    ,CD.DateOfArrival

    ,CD.DateOfDeparture;

    Results

    ID number DateOfArrival DateOfDeparture JAN14 FEB14 MAR14 APR14 MAY14 JUN14 JUL14 AUG14 SEP14 OCT14 NOV14 DEC14

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

    1056 2014-04-29 2014-05-03 0 0 0 1 3 0 0 0 0 0 0 0

    2031 2014-03-20 2014-03-26 0 0 6 0 0 0 0 0 0 0 0 0

    3245 2014-06-19 2014-06-20 0 0 0 0 0 1 0 0 0 0 0 0

    Hi Eirikur,

    I do have another issue with the solution you provided. It is just now that I am realising the output in your solution is not correct when the duration of stay concerns 2 consecutive months. In your output, row 1 gives 1 for Apr14 and 3 for May14.

    In fact it should be 2 for Apr14 and 2 for May14, meaning the guest stayed 2 nights in Apr14 and 2 nights in May14.

    Can you point out how to modify the code to correct for this?

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

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