【问题标题】:Calculating a daily average (or: how many Mondays are in a date range?)计算每日平均值(或:日期范围内有多少个星期一?)
【发布时间】:2012-02-29 00:34:26
【问题描述】:

我的 MySQL 表有以下列:datetime、price_paid。 我正在尝试计算两个日期之间一周中每天的平均销售额。 这意味着我需要选择日期 startDate 和 endDate 之间的销售额总和,按工作日分组,然后除以该范围内每个工作日出现的次数。

我得到了第一部分:

SELECT DATE_FORMAT(datetime, '%a') AS field1, 
round(SUM(price_paid)/ THEVALUEIMLOOKINGFOR ) AS field2 
FROM Bills 
WHERE date(datetime) BETWEEN '2012-01-02' AND '2012-01-09' 
GROUP BY weekday(datetime)

我没有的是缺失值:我应该除以的数字 - 每天出现在该范围内的次数。我尝试了几种解决方案,但无济于事。

有人可以帮我完成我的 SQL 语句吗?

感谢您的宝贵时间!

【问题讨论】:

  • 那么,您最终是否希望在日期范围内查看每日平均值:周一、周二、周三等...?如果是这样,某些范围可能只有 2 周三与 3 周一和周二(或其他类似)...
  • 正确 - 我需要一个每日平均值。我希望下面的解决方案考虑到这一点

标签: mysql sql datetime


【解决方案1】:

也许我太简单了,但鉴于您已经按工作日分组,难道不只是 count(*) 计算每个工作日在该范围内给定工作日的数量吗?

所以:

SELECT DATE_FORMAT(datetime, '%a') AS field1, 
round(SUM(price_paid)/ COUNT(DISTINCT(date(datetime))) ) AS field2 
FROM Bills 
WHERE date(datetime) BETWEEN '2012-01-02' AND '2012-01-09' 
GROUP BY weekday(datetime)

已编辑,因此不会在同一天多次多算(感谢 DRapp)

【讨论】:

  • 我认为你非常接近......但是,如果他们在同一日期有多个账单,你会多算除数。格式化 yyyy-mm-dd 上的 COUNT(DISTINCT) 将有助于确保...
  • 那么COUNT(DISTINCT(date(datetime))
  • 感谢您的回答。但是有一个问题:这是否涵盖日期范围为 8 天(即有 2 个星期一)的情况,因此您需要划分购买 2 个星期一? Distinct 还有必要吗?
  • @TravelingTechGuy,应该是正确的。如果 8 天,两个星期一的总数将除以 2...但是,周二至周日将全部除以 1 个实例...运行一些示例数据,您应该会很好。
【解决方案2】:

我知道这很旧,但“似乎有效”。还不够好。 事实上,如果有一天的交易为零,它将低估星期一的数量。

有一个公式可以计算日期范围内的星期几。您需要从一周中的已知日期开始。 “1970-01-05”是星期一。

这是一个你可以使用的函数:

create function CountDaysOfWeek(
    DateFrom DATETIME,
    DateTo DATETIME,
    DayOfWeek int
)
RETURNS int
return FLOOR(DATEDIFF(DateTo,'1970-01-03' + INTERVAL DayOfWeek DAY)/7) - 
   FLOOR(DATEDIFF(DateFrom,'1970-01-03' + INTERVAL (DayOfWeek+1) DAY)/7);

【讨论】:

    【解决方案3】:

    这是一个名为 MakeDateList 的存储函数:

    DELIMITER $$
    DROP FUNCTION IF EXISTS `junk`.`MakeDateList` $$
    
    CREATE FUNCTION `junk`.`MakeDateList`
    (
      BeginDate DATE,
      EndDate DATE,
      InclusionList VARCHAR(20)
    )
    
    RETURNS VARCHAR(4096)
    DETERMINISTIC
    BEGIN
      DECLARE RunningDate DATE;
      DECLARE rv VARCHAR(4096);
      DECLARE comma CHAR(1);
      DECLARE IncList,DOWValue VARCHAR(20);
      DECLARE OK_To_Add INT;
    
      SET IncList = CONCAT(',',InclusionList,',');
      SET comma = '';
      SET rv = '';
      SET RunningDate = BeginDate;
    
      WHILE RunningDate <= EndDate DO
        SET OK_To_Add = 0;
        SET DOWValue = CONCAT(',',DAYOFWEEK(RunningDate),',');
        IF LOCATE(DOWValue,IncList) > 0 THEN
          SET OK_To_Add = 1;
        END IF;
        IF OK_To_Add = 1 THEN
           SET rv = CONCAT(rv,comma,RunningDate);
        END IF;
        SET comma = ',';
        SET RunningDate = RunningDate + INTERVAL 1 DAY;
      END WHILE;
    RETURN rv;
    END $$
    DELIMITER ;
    

    它有三个参数:BeginDate、EndDate和InclusionList

    InclusionList 是逗号分隔的数字列表(有效数字 1-7)

    1 = Sunday
    2 = Monday
    3 = Tuesday
    4 = Wednesday
    5 = Thursday
    6 = Friday
    7 = Saturday
    

    所以要获得星期一,请将 InclusionList 设为 2

    示例:调用 MakeDateList('2011-10-01','2011-10-01','2') 应该为您提供 2011 年 10 月整个月的星期一

    【讨论】:

      【解决方案4】:

      由于您需要平均值的总和,因此您需要使用子查询来计算每天的平均值,然后计算平均值的总和。

      我已修改查询以包含一个返回平均值总数的外部查询。但是现在 field1 将不再有意义,因为它可以是任何日期,具体取决于您使用的订购选项

      SELECT field1, SUM (field2) FROM (
        SELECT DATE_FORMAT(datetime, '%a') AS field1, 
        AVG(price_paid) AS field2 
        FROM Bills 
        WHERE date(datetime) BETWEEN '2012-01-02' AND '2012-01-09' 
        GROUP BY weekday(datetime)
      ) 
      

      【讨论】:

      • 试过这个。这将返回每 a 天的平均值,而不是平均值的总数。谢谢
      猜你喜欢
      • 2019-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 1970-01-01
      • 2021-12-29
      相关资源
      最近更新 更多