SQL Find Count of Records by Day and By User

3.2k views Asked by At

I am trying to find the count of days listed by person where they have over 100 records in the recordings table. It is having a problem with the having clause, but I am not sure how else to distinguish the counts by person. There is also a problem with the where clause, I also tried putting "where Count(Recordings.ID) > 100" and that did not work either. Here is what I have so far:

SELECT Person.FirstName,
       Person.LastName,
       Count(Recordings.ID) AS DAYS_ABOVE_100
FROM   Recordings
JOIN   Person ON Recordings.PersonID=Person.ID
WHERE  DAYS_ABOVE_100 > 100
AND    Created BETWEEN '2013-08-01 00:00:00.000' AND '2013-08-21 00:00:00.000'
GROUP  BY Person.FirstName,
       Person.LastName
HAVING Count(DISTINCT PersonID), Count(Distinct Datepart(day, created))
ORDER  BY DAYS_ABOVE_100 DESC

Example data of what I want to get:

First  Last    Days_Above_100
John   Doe     5
Jim    Smith   12

This means that for 5 of the days in the given time frame, John Doe had over 100 records each day.

4

There are 4 answers

1
Charles On BEST ANSWER

For the sake a readability, I would break the problem into two parts.

First, figure out how many recordings each person has for a day. This is the query in the common table expression (the first select statement). Then select against the common table expression to limit the rows to only those that you need.

with cteRecordingsByDate as
(
  SELECT Person.FirstName,
        Person.LastName,
        cast(created as date) as Whole_date,
        Count(Recordings.ID) AS Recording_COUNT
  FROM   Recordings
  JOIN   Person ON Recordings.PersonID=Person.ID
  WHERE  Created BETWEEN '2013-08-01 00:00:00.000' AND '2013-08-21 00:00:00.000'
  GROUP  BY  Person.FirstName, Person.LastName, cast(created as date)
)

select FirstName, LastName, count(*) as Days_Above_100
from cteRecordingsByDate
where Recording_COUNT > 100
order by count(*) desc
2
Gordon Linoff On

You can count what you want using a subquery. The inner query counts the number of records per day. The outer subquery then counts the number of days that exceed 100 (and adds in the person information as well):

SELECT p.FirstName, p.LastName,
       count(*) as DaysOver100
FROM (select PersonId, cast(Created as Date) as thedate, count(*) as NumRecordings
      from Recordings r
      where Created BETWEEN '2013-08-01 00:00:00.000' AND '2013-08-21 00:00:00.000'
     ) r join
     Person p
     ON r.PersonID = p.ID
WHERE r.NumRecordings > 100
GROUP BY p.FirstName, p.LastName;

This uses SQL Server syntax for the conversion from datetime to date. In other databases you might use trunc(created) or date(created) to extract the date from a datetime.

1
MACN On

You should try this:

 SELECT SUBQUERY.FirstName,
        SUBQUERY.LastName,
        Count(*) AS DAYS_ABOVE_100
 FROM
 (
     SELECT Person.FirstName,
            Person.LastName,
            Count(Recordings.ID) AS COUNT_RECORDINGS
     FROM   Recordings
     JOIN   Person ON Recordings.PersonID=Person.ID
     WHERE  Created BETWEEN '2013-08-01 00:00:00.000' AND 
                            '2013-08-21 00:00:00.000'
     GROUP  BY Person.FirstName,
               Person.LastName,
               Created 
     HAVING Count(Recordings.ID) > 100
 )SUBQUERY
 GROUP  BY SUBQUERY.FirstName,
           SUBQUERY.LastName
 ORDER  BY Count(*) DESC

Think that the Having clause works like a Where clause, but one that accept aggregates, like sum (source). Your query had some errors,namely :

  • An aggregate in the WHERE clause, but the Where clause do not accept aggregates.
  • You were refering to the aggregate "Count(Recordings.ID)" by it alias "DAYS_ABOVE_100" in the ORDER BY clause. You cannot access a column by its alias inside the same select where you defined that alias. Columns can only be accessed by their alias from outside the query, like in Charles's answer.

EDIT:

Sorry, I didn't noticed the "by day" part, edited the query. Added created column to GROUP BY clause to obtain total records per day, then wrapped it in another query to count the results, grouping again by FirstName and Lastname.

0
Hart CO On

I think this is what you're after:

SELECT p.FirstName,
       p.LastName,
       COUNT(*) AS DAYS_ABOVE_100
FROM   (SELECT PersonID, Created, COUNT(*)
        FROM Recordings
        GROUP BY ID,Created
        HAVING COUNT(*) > 100
        )r
JOIN   Person p
  ON r.PersonID = p.ID
WHERE  Created BETWEEN '2013-08-01 00:00:00.000' AND '2013-08-21 00:00:00.000'
GROUP  BY p.FirstName,
          p.LastName
ORDER  BY DAYS_ABOVE_100 DESC