September 23, 2014 at 1:32 pm
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?
September 23, 2014 at 2:13 pm
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()?
September 23, 2014 at 2:43 pm
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
September 23, 2014 at 4:17 pm
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!
September 23, 2014 at 4:53 pm
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;
September 23, 2014 at 5:23 pm
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.
September 23, 2014 at 11:46 pm
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?
September 24, 2014 at 1:03 am
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)
)
September 24, 2014 at 9:05 am
Thanks, Eirikur! Got it now! I should have read more attentively! Thanks again! π
September 24, 2014 at 11:58 am
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.;-)
π
September 26, 2014 at 1:23 am
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?
September 26, 2014 at 2:14 am
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.
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
September 26, 2014 at 10:19 am
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.
September 27, 2014 at 6:19 am
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 ','.
September 27, 2014 at 7:55 am
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