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.
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.
The SQL COUNT(), AVG() and SUM() Functions. The COUNT() function returns the number of rows that matches a specified criteria.
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:
The AVG () function returns the average value of a numeric column. The SUM () function returns the total sum of a numeric column.
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With