2010-08-05 185 views
1

我有跨越多个月的数据,我希望能够将每天的平均值分成适当的月份。例如,假设一个数据点是2010年2月9日 - 2010年3月8日,数量是1500.那么,查询应该返回2010年2月的1071.4和3月的428.6。我希望有一个MySQL语句能够完成计算,而不是我的PHP逻辑。谢谢。如果月度数据跨越一个月以上,MySQL如何计算每月平均值?

编辑(添加表定义): 开始(日期时间),端部(日期时间),使用

编辑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; 
+0

你能发表表格定义的相关部分吗? – 2010-08-05 19:11:17

回答

1

该溶液处理小一(1)天的[start_date, end_date]跨度和一样大十二(12)个月,但是不正确上的13(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_name | month_amount | 
+----+------------+---------------+ 
| 1 | January | 187.87878788 | 
| 1 | February | 12.12121212 | 
| 2 | February | 250.00000000 | 
| 3 | February | 81.81818182 | 
... 

我们使用DATEDIFF来确定源记录所代表的天数。然后,建立一个integers table,我们可以在特定的范围内列举每一天的月份。从那里,它是由记录idmonth_name SQL聚合的问题。

+0

由于某种原因,我的输出是 1 Janurary 60.6, 2 Feburary 108.69 我无法得到它来复制您的输出。 此外,我需要能够跨越13个或更多个月。是否有解决方案可以解决这个问题? – Kramer 2010-08-06 14:26:48

+0

@Kramer,你的输出问题是因为你的“整数”表的值只有0-9,而我依靠的是0-999,现在我意识到,这并不是由我提供的链接建议的。我会澄清。 – pilcrow 2010-08-06 16:33:12

+0

@Kramer,要处理一年以上的跨度,您需要为最内层的子查询添加一个“YEAR(start_date + INTERVAL ...)”,以及GROUP BY和ORDER BY以及... – pilcrow 2010-08-07 00:38:39

1

应该由选择SUM和组MONTH(日期)功能如下:

SELECT SUM(value), MONTH(date) 
FROM TABLE 
GROUP BY MONTH(date) 

编辑:哎呀,我误读了这个问题,现在就修改我的答案!

你需要使用一些更复杂的TSQL得到天的几个月里,求其平均值,并设置成每个字段,然后在每月的格式

更新 目前它创建一个函数来给你在你的范围内的天像这样的,这是我从迈克尔·巴里亚创建一个功能修改

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 @[email protected] 

--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 

加入你的表给这个函数再总结基础上,天

SELECT SUM(data/DATEDIFF(dd,startDate,endDate)), M.MonthValue 
FROM TABLE 
JOIN (SELECT * FROM [dbo].[GetDays] (startDate,endDate)) M 

GROUP BY M.MonthValue 

,如果我得到一些样本数据

+0

马修,我已经添加了一些示例数据 – Kramer 2010-08-05 19:58:03

+0

谢谢。我的答案应该是有效的解决方案。让我知道是否需要进一步澄清 – Matthew 2010-08-05 20:18:53

+0

这个问题涉及MySQL,这个答案似乎是特定于MS-SQL。 – pilcrow 2010-08-06 12:27:21

0

但这在过去几个月的量分开,我可以打扫一下了一下:

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 

它变得有点但更复杂的是,因为首先必须检查日期是否实际上处于不同的月份,并且如果日期跨越两个月以上,则需要采用不同的方法。