Sql 从一个月以上的数据中获取数据时,平均值太高
我被要求修改一个查询,以处理来自给定日期选择的数据,而不仅仅是当前月份的数据。查询应获取该日期范围内每小时的平均销售额。当选择一个月的数据时,它似乎工作得很好,但当我尝试去选择一个月以上的数据时,平均值似乎高于它们应该达到的水平 我认为问题可能与按天分组有关,因为当数据超过一个月时,这一天将加倍,但我将如何着手解决它?提前谢谢Sql 从一个月以上的数据中获取数据时,平均值太高,sql,sql-server,Sql,Sql Server,我被要求修改一个查询,以处理来自给定日期选择的数据,而不仅仅是当前月份的数据。查询应获取该日期范围内每小时的平均销售额。当选择一个月的数据时,它似乎工作得很好,但当我尝试去选择一个月以上的数据时,平均值似乎高于它们应该达到的水平 我认为问题可能与按天分组有关,因为当数据超过一个月时,这一天将加倍,但我将如何着手解决它?提前谢谢 DECLARE @Start DATETIME DECLARE @End DATETIME SET @Start = '6/15/2015' SET @End = '8
DECLARE @Start DATETIME
DECLARE @End DATETIME
SET @Start = '6/15/2015'
SET @End = '8/15/2015'
SELECT TheHour, AVG(TheCount) AS SalesPerHour
FROM
(SELECT DATEPART(DAY, DateTimeCreated) AS TheDay,
DATEPART(HOUR, DateTimeCreated) AS TheHour,
COUNT(*) AS TheCount
FROM OrderHeader
WHERE Deleted = 0
AND OrderType = 1
AND BranchID = 4
AND BackOrderedFromID IS NULL
AND DateTimeCreated >= @Start
AND DateTimeCreated < @End
GROUP BY DATEPART(DAY, DateTimeCreated), DATEPART(HOUR, DateTimeCreated)) AS T
GROUP BY TheHour
ORDER BY TheHour
2015年7月15日至2015年8月15日的样本数据
TheHour SalesPerHour
5 1
6 7
7 6
8 5
9 4
10 4
11 4
12 2
13 4
14 2
15 1
2015年6月15日至2015年8月15日的样本数据大多数值是否过高
TheHour SalesPerHour
5 2
6 10
7 11
8 8
9 7
10 6
11 5
12 3
13 5
14 4
15 2
16 1
要将日期时间舍入到最接近的整小时,请同时使用DATEADD和DATEDIFF:
DECLARE @Start DATETIME
DECLARE @End DATETIME
SET @Start = '6/15/2015'
SET @End = '8/15/2015'
SELECT DATEPART(hour,RoundedHour) as Hour, AVG(TheCount) AS SalesPerHour
FROM
(SELECT DATEADD(hour,DATEDIFF(hour,0,DateTimeCreated),0) as RoundedHour,
COUNT(*) AS TheCount
FROM OrderHeader
WHERE Deleted = 0
AND OrderType = 1
AND BranchID = 4
AND BackOrderedFromID IS NULL
AND DateTimeCreated >= @Start
AND DateTimeCreated < @End
GROUP BY DATEADD(hour,DATEDIFF(hour,0,DateTimeCreated),0)) AS T
GROUP BY DATEPART(hour,RoundedHour)
ORDER BY DATEPART(hour,RoundedHour)
这样,您就不必考虑所有较大的组成部分—天、月、年,您也可以根据这些组成部分进行分组,以获得更大的范围。不要使用datepartday。这是一个月的哪一天。当您的时间范围跨越多个月时,datepartday会为不同的日期返回相同的值,例如,在任何月份的第一天返回1
相反,只需将值强制转换为日期即可删除时间组件。查询的其余部分保持不变:
SELECT TheHour, AVG(TheCount) AS SalesPerHour
FROM (SELECT CAST(DateTimeCreated as Date) AS TheDay,
DATEPART(HOUR, DateTimeCreated) AS TheHour,
COUNT(*) AS TheCount
FROM OrderHeader
WHERE Deleted = 0 AND OrderType = 1 AND BranchID = 4 AND
BackOrderedFromID IS NULL AND
DateTimeCreated >= @Start
DateTimeCreated < @End
GROUP BY CAST(DateTimeCreated as Date), DATEPART(HOUR, DateTimeCreated)
) dh
GROUP BY TheHour
ORDER BY TheHour;
或者,您可以在不使用双重聚合的情况下执行此操作:
SELECT DATEPART(HOUR, DateTimeCreated) as TheHour,
(COUNT(*) * 1.0 /
COUNT(DISTINCT CAST(DateTimeCreated as Date))
) as SalesPerHour
FROM OrderHeader oh
WHERE Deleted = 0 AND OrderType = 1 AND BranchID = 4 AND
BackOrderedFromID IS NULL AND
DateTimeCreated >= @Start
DateTimeCreated < @End
GROUP BY DATEPART(HOUR, DateTimeCreated);
另外,请注意,整数值的平均值是整数平均值。因此,在SQL Server中,1和2的平均值是1,而不是1.5。在此版本中,查询将计数乘以1.0以获得小数位-这可能是可取的,也可能是不可取的。由于您的查询使用日作为日期部分,因此在获得平均值之前,您实际上是在添加每天每小时的销售额。例如,如果一名销售人员在1月1日下午5点的时间内有10次销售,2月1日下午5点的时间内有12次销售,那么第1天的中间值为22次销售。你最终会在每个月的几天内平均这些,但不是在这些天本身
您可以改为使用DY day of year的DATEPART,但是如果您开始跨越年份,那么您的查询将遇到相同的问题。相反,只需将DATETIME转换为日期,以消除时间部分,或者更好的是,使用窗口函数获取数字,如下所示:
;WITH CTE_HourBreakdown AS
(
SELECT
DATEPART(HOUR, DateTimeCreated) AS hr,
COUNT(*) OVER (PARTITION BY (YEAR(DateTimeCreated), DATEPART(DY, DateTimeCreated), DATEPART(HOUR, DateTimeCreated)) AS cnt
FROM
OrderHeader
)
SELECT
hr,
AVG(CAST(cnt AS DECIMAL(10, 2)))
FROM
CTE_HourBreakdown
GROUP BY
hr
可能有一种更好的方法可以使用窗口函数实现这一点,但这是我想到的第一件事。另外,请注意,如果一小时内没有销售,此方法不会将其平均值计入结果。例如,如果在下午4点到5点之间的某一天没有销售,而第二天有2次销售,那么将显示下午4点到5点之间的平均销售为2次,而不是平均销售1次。如果你想说明这一点,那么你需要一种方法来区分零销售小时数和无人工作时的小时数。我建议将AVG计数更改为简单计数,然后按此计数分组以查看平均数据。我建议你查看子查询结果,而不是完整的查询结果。这将给你一个线索,你是什么数据AVGThanks!您的查询非常有效,它提出了一个有趣的取整点,我以前甚至没有考虑过。谢谢您的帮助。我以后一定会记住这一点,因为这确实让思考变得更简单。DISTINCT是测试语句时留下的,已经被删除。
;WITH CTE_HourBreakdown AS
(
SELECT
DATEPART(HOUR, DateTimeCreated) AS hr,
COUNT(*) OVER (PARTITION BY (YEAR(DateTimeCreated), DATEPART(DY, DateTimeCreated), DATEPART(HOUR, DateTimeCreated)) AS cnt
FROM
OrderHeader
)
SELECT
hr,
AVG(CAST(cnt AS DECIMAL(10, 2)))
FROM
CTE_HourBreakdown
GROUP BY
hr