TSQL: Невозможно выполнить агрегатную функцию AVG для COUNT (*), чтобы найти наиболее загруженные часы дня - PullRequest
5 голосов
/ 13 ноября 2009

Рассмотрим таблицу SQL Server, в которой хранятся данные журнала. Важные части:

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]

Запрос здесь заключается в поиске распределения посещений ПО ЧАСУ дня. Мы заинтересованы в том, чтобы увидеть распределение среднего числа посещений за час в заданном диапазоне дат. Visits sample

Результаты запроса будут выглядеть примерно так:

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

Намерение состоит в том, чтобы написать запрос следующим образом :

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

Однако это неверный запрос:

Невозможно выполнить агрегатную функцию для выражения, содержащего агрегат или подзапрос.

Вопрос: как бы вы переписали этот запрос для сбора средних итогов (т. Е. Вместо AVG(COUNT(*)) за час?

Представьте себе, что результаты этого запроса будут переданы PHB , который хочет узнать, какие самые загруженные часы дня .

  • SQL Server 2005 +

Ответы [ 2 ]

7 голосов
/ 13 ноября 2009

Использование встроенного просмотра:

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)

Использование эквивалента CTE (SQL Server 2005+):

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)
0 голосов
/ 14 ноября 2009

Количество дней известно и равно DATEDIFF(day,CONVERT(DATETIME,'2009.01.01',120),CONVERT(DATETIME,'2009.09.01',120)). Вы должны рассчитать сумму и разделить ее на количество дней в выбранном диапазоне:

SELECT  
  DATEPART(hh, VisitDate),
  CAST(COUNT(*) AS FLOAT) / DATEDIFF(day,CONVERT(DATETIME,'2009.01.01',120),CONVERT(DATETIME,'2009.09.01',120))
FROM CustomerLog
WHERE 
  (VisitDate >= CONVERT(DATETIME,'2009.01.01',120)) AND 
  (VisitDate < CONVERT(DATETIME,'2009.09.01',120))  
GROUP BY DATEPART(hh, VisitDate)

CAST(COUNT(*) AS FLOAT), чтобы получить более точный результат, но вы можете оставить только COUNT(*) и получить целочисленный результат.

Если вы используете параметры, это будет:

SELECT  
  DATEPART(hh, VisitDate),
  CAST(COUNT(*) AS FLOAT) / DATEDIFF(day,@beginningDate,@endDate)
FROM CustomerLog
WHERE 
  (VisitDate >= @beginningDate) AND 
  (VisitDate < @endDate)  
GROUP BY DATEPART(hh, VisitDate)

Если вы хотите результаты за январь, вы должны использовать @beginningDate = '2009.01.01', @endDate = '2009.02.01'.

...