考虑一个包含日志数据的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]
此处的查询是查找当天的访问分布按小时。我们有兴趣查看给定日期范围内小时 的平均访问次数的分布情况。
查询结果如下:
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,{{3}}想知道当天最忙碌的小时。
答案 0 :(得分:7)
使用内联视图:
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)
答案 1 :(得分:0)
已知天数,它等于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)
如果你想要1月的结果,你必须使用@beginningDate ='2009.01.01',@ endDate ='2009.02.01'。