Math 对于跨越一个月以上的月度数据,如何在MySQL中计算月度平均值?

Math 对于跨越一个月以上的月度数据,如何在MySQL中计算月度平均值?,math,mysql,Math,Mysql,我有跨越多个月的数据,我希望能够获得每天的平均值,并将其分离到适当的月份。例如,假设一个数据点为2010年9月2日-2010年8月3日,数量为1500。然后,查询应返回2010年2月的1071.4和3月的428.6。我希望有一个MySQL语句能够代替我的PHP逻辑进行计算。谢谢 编辑(添加了表定义): 开始(日期时间),结束(日期时间),使用 编辑2:下面是一些虚拟数据 DROP TABLE IF EXISTS `dummy_data`; CREATE TABLE `dummy_data`

我有跨越多个月的数据,我希望能够获得每天的平均值,并将其分离到适当的月份。例如,假设一个数据点为2010年9月2日-2010年8月3日,数量为1500。然后,查询应返回2010年2月的1071.4和3月的428.6。我希望有一个MySQL语句能够代替我的PHP逻辑进行计算。谢谢

编辑(添加了表定义): 开始(日期时间),结束(日期时间),使用

编辑2:下面是一些虚拟数据



DROP TABLE IF EXISTS `dummy_data`;
CREATE TABLE `dummy_data` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `start_date` date NOT NULL,
  `end_date` date NOT NULL,
  `data` double(15,4) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;

-- ----------------------------
--  Records of `dummy_data`
-- ----------------------------
BEGIN;
INSERT INTO `dummy_data` VALUES ('1', '2010-01-01', '2010-02-02', '200.0000'), ('2', '2010-02-03', '2010-02-25', '250.0000'), ('3', '2010-02-26', '2010-03-08', '300.0000'), ('4', '2010-03-09', '2010-04-12', '210.0000'), ('5', '2010-04-13', '2010-05-10', '260.0000'), ('6', '2010-05-11', '2010-06-15', '310.0000'), ('7', '2010-06-16', '2010-07-20', '320.0000');
COMMIT;

您应选择“按月(日期)汇总和分组”功能,如下所示:

SELECT SUM(value), MONTH(date)
FROM TABLE
GROUP BY MONTH(date)
编辑:哎呀,我看错了问题,现在修改我的答案

您需要使用一些更复杂的TSQL来获取月份中的天数,找到平均值并设置到每个字段中,然后以每月格式显示

更新 创建一个函数,在您的范围内为您提供天数,例如,我从Michael Baria创建的函数中修改了这个函数

CREATE FUNCTION [dbo].[GetDays](@StartDate DATETIME, @EndDate DATETIME)
RETURNS @MonthList TABLE(DayValue tinyint NOT NULL, MonthValue tinyint NOT NULL, YearValue int NOT NULL)
AS
BEGIN
--Variable used to hold each new date value
DECLARE @DateValue DATETIME

--Start with the starting date in the range
SET @DateValue=@StartDate

--Load output table with the month part of each new date
WHILE @DateValue <= @EndDate
BEGIN
    INSERT INTO @MonthList(DayValue, MonthValue,YearValue)
    SELECT DAY(@DateValue), MONTH(@DateValue), YEAR(@DateValue)

    --Move to the next day           
    SET @DateValue=DATEADD(dd,1,@DateValue)
END

--Return results
RETURN
END

GO

如果我得到一些样本数据,我可以稍微清理一下这一点。这确实会将几个月的金额分开:

declare @start datetime set @start = '20100209'
declare @end datetime set @end = '20100308'
declare @avg float set @avg = 1500

select
datediff(day, @start, dateadd(day, 1-day(@end), @end)) * @avg / (datediff(day, @start, @end) + 1),
datediff(day, dateadd(day, -day(@end), @end), @end) * @avg / (datediff(day, @start, @end) + 1)
结果:

1071,42857142857    428,571428571429

但它变得有点复杂,因为您首先必须检查日期是否在不同的月份,如果日期跨越两个月以上,则需要不同的方法。

此解决方案处理的
[开始日期,结束日期]
跨度小到一(1)天,大到十二(12)个月,但在十三(13)个月或更长时间内不正确:

CREATE TABLE integers (i INT NOT NULL);

INSERT INTO integers VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);

CREATE VIEW hundreds AS
   SELECT iii.i * 100 + ii.i * 10 + i AS i
     FROM integers i JOIN integers ii JOIN integers iii;

-- We do not have CTEs, so we create a view
CREATE VIEW spans AS
   SELECT id, start_date, DATEDIFF(end_date, start_date) + 1 AS ndays, data
     FROM dummy_data;

   SELECT spans.id,
          month_name,
          spans.data * COUNT(month_name)/spans.ndays AS month_amount
     FROM spans
LEFT JOIN (SELECT id,
                  MONTH(start_date + INTERVAL i DAY) AS month_num,
                  MONTHNAME(start_date + INTERVAL i DAY) AS month_name
             FROM spans
             JOIN hundreds WHERE i < ndays) daybyday
       ON spans.id = daybyday.id
 GROUP BY id, month_name
 ORDER BY id, month_num;

我们使用来确定源记录表示的天数。然后,建立一个函数,我们可以列举特定跨度内每天的月份。从这里开始,就需要通过记录
id
month\u name

进行SQL聚合,您可以发布表定义的相关部分吗?Matthew,我添加了一些示例数据谢谢。我的答案应该是一个有效的解决方案。如果需要进一步澄清,请告诉我这个问题与MySQL有关,这个答案似乎是针对MS-SQL的。Matthew,你能将你的解决方案转换为MySQL吗?出于某种原因,我的输出是1月1日60.6,2月2日108.69,我无法让它复制你的输出。此外,我需要能够跨越13个月或更长的时间。您的解决方案是否有解决方案允许这样做?@Kramer,您的输出问题是因为您的“integers”表只有0-9个值,而我依赖于0-999,我现在意识到,我提供的链接并不建议使用0-999。我要澄清一下。@Kramer,要处理超过一年的跨度,您需要在最内层的子选择中添加一个
年(开始日期+间隔…
,并按此分组和排序。。。
CREATE TABLE integers (i INT NOT NULL);

INSERT INTO integers VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);

CREATE VIEW hundreds AS
   SELECT iii.i * 100 + ii.i * 10 + i AS i
     FROM integers i JOIN integers ii JOIN integers iii;

-- We do not have CTEs, so we create a view
CREATE VIEW spans AS
   SELECT id, start_date, DATEDIFF(end_date, start_date) + 1 AS ndays, data
     FROM dummy_data;

   SELECT spans.id,
          month_name,
          spans.data * COUNT(month_name)/spans.ndays AS month_amount
     FROM spans
LEFT JOIN (SELECT id,
                  MONTH(start_date + INTERVAL i DAY) AS month_num,
                  MONTHNAME(start_date + INTERVAL i DAY) AS month_name
             FROM spans
             JOIN hundreds WHERE i < ndays) daybyday
       ON spans.id = daybyday.id
 GROUP BY id, month_name
 ORDER BY id, month_num;
+----+------------+---------------+
| id | month_name | month_amount  |
+----+------------+---------------+
|  1 | January    |  187.87878788 | 
|  1 | February   |   12.12121212 | 
|  2 | February   |  250.00000000 | 
|  3 | February   |   81.81818182 | 
...