Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TSQL: Cannot perform an aggregate function AVG on COUNT(*) to find busiest hours of day

Consider a SQL Server table that holds log data. The important parts are:

CREATE TABLE [dbo].[CustomerLog](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [CustID] [int] NOT NULL,
    [VisitDate] [datetime] NOT NULL,
 CONSTRAINT [PK_CustomerLog] PRIMARY KEY CLUSTERED ([ID] ASC)) ON [PRIMARY]

The query here is around finding the distribution of visits BY HOUR of the day. We're interested in seeing the distribution of the average number of visits for the hour in a given date range. Visits sample

The query results would be something like this:

HourOfDay   Avg.Visits.In.Hour
0            24
1            16
5            32
6            89
7           823
etc.etc.

The intention is to write a query like this:

SELECT  DATEPART(hh, VisitDate)
        ,AVG(COUNT(*))    
FROM    CustomerLog
WHERE   VisitDate   BETWEEN 'Jan 1 2009' AND 'Aug 1 2009'
GROUP BY   DATEPART(hh, VisitDate)

This is not a valid query, however:

Cannot perform an aggregate function on an expression containing an aggregate or a subquery.

Question: how would you re-write this query to gather the average totals (i.e. in place of AVG(COUNT(*)) for the hour?

Imagine this query's results would be handed to a PHB who wants to know what the busiest hours of the day are.

  • SQL Server 2005+
like image 787
p.campbell Avatar asked Nov 13 '09 18:11

p.campbell


People also ask

What are the functions of Count () and AVG () in SQL Server?

The SQL COUNT(), AVG() and SUM() Functions. The COUNT() function returns the number of rows that matches a specified criteria.

What is an aggregate function in SQL?

An aggregate function in SQL performs a calculation on multiple values and returns a single value. SQL provides many aggregate functions that include avg, count, sum, min, max, etc. An aggregate function ignores NULL values when it performs the calculation, except for the count function. In this article, we will discuss the following topics:

What is the difference between avg () and sum () functions in MySQL?

The AVG () function returns the average value of a numeric column. The SUM () function returns the total sum of a numeric column.

What is the difference between Min () and Max () aggregate functions?

The MIN () aggregate function returns the lowest value (minimum) in a set of non-NULL values. The above code will give us the minimum quantity in stock in the products table. The MAX () aggregate function returns the highest value (maximum) in a set of non-NULL values.


1 Answers

Using inline view:

SELECT DATEPART(hh, x.visitdate),
       AVG(x.num)
  FROM (SELECT t.visitdate,
               COUNT(*) 'num'
          FROM CUSTOMERLOG t
         WHERE t.visitdate BETWEEN 'Jan 1 2009' AND 'Aug 1 2009'
      GROUP BY t.visitdate) x
GROUP BY DATEPART(hh, x.visitdate)

Using CTE (SQL Server 2005+) equivalent:

WITH visits AS (
   SELECT t.visitdate,
          COUNT(*) 'num'
     FROM CUSTOMERLOG t
    WHERE t.visitdate BETWEEN 'Jan 1 2009' AND 'Aug 1 2009'
 GROUP BY t.visitdate)
   SELECT DATEPART(hh, x.visitdate),
         AVG(x.num)
    FROM visits x
GROUP BY DATEPART(hh, x.visitdate)
like image 121
OMG Ponies Avatar answered Sep 28 '22 02:09

OMG Ponies