I am trying to get the query for getting the count of users every hour of day in the table. If the data for that hour is not present, I want to record the hour with count of zero. Also users should be counted only for their first entry. Subsequent entries should be ignored.
Table:
userId creationDate
1 2014-10-08 14:33:20.763
2 2014-10-09 04:24:14.283
3 2014-10-10 18:34:26.260
Desired output:
Date UserCount
2014-10-08 00:00:00.000 1
2014-10-08 01:00:00.000 1
2014-10-08 02:00:00.000 1
2014-10-08 03:00:00.000 0
2014-10-08 04:00:00.000 1
....
.....
2014-10-10 23:00:00.000 1
2014-10-10 00:00:00.000 0
My attempt:
SELECT
CAST(creationDate as date) AS ForDate,
DATEPART(hour, date) AS OnHour,
COUNT(distinct userId) AS Totals
FROM
Table
WHERE
primaryKey = 123
GROUP BY
CAST(creationDate as date), DATEPART(hour, createDate)
This only gives me per hour for the record that is present. Not the data for the missing hours. I think there is a way by using a cross join to get 0 data even for the missing hours.
Something like this, I came across, but not able to construct a proper query with it.
cross join (select
ROW_NUMBER() over (order by (select NULL)) as seqnum
from
INFORMATION_SCHEMA.COLUMNS) hours
where hours.seqnum >= 24
Once again, I am not a SQL expert, but trying hard to construct this result set.
One more attempt :
with dh as (
select DATEADD(hour, seqnum - 1, thedatehour ) as DateHour
from (select distinct cast(cast(createDate as DATE) as datetime) as thedatehour
from Table a
) a
cross join
(select ROW_NUMBER() over (order by (select NULL)) as seqnum
from INFORMATION_SCHEMA.COLUMNS
) hours
where hours.seqnum (less than)= 24
)
select dh.DateHour, COUNT(distinct c.userId)
from dh cross join Table c
--on dh.DateHour = c.createDate
group by dh.DateHour
order by 1
I asked a similar question on dba just this morning...https://dba.stackexchange.com/questions/86435/filling-in-date-holes-in-grouped-by-date-sql-data. You can used my GetSequence function, or create a Numbers table. I haven't done my own testing yet to validate what was suggested in my scenario.
Try this:
BUILD SAMPLE DATA
SOLUTION
CLEANUP
Create a temporary table (let's say
#CreationDateHours
) containing create date and hours from 0 to 23.Now, Run this query to get the desired results
You need to build up a table of possible hours, and then join this to your actual records.
The best way to build up a table of possible hours is to use a recursive common table expression. Here's how:
NB - DATETIMEFROMPARTS is only in SQL SERVER 2012 and greater. If you are using an earlier version of SQL SERVER you could have