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