Как рассчитать среднемесячное значение в MySQL с учетом месячных данных, охватывающих более одного месяца? - PullRequest
2 голосов
/ 05 августа 2010

У меня есть данные, которые охватывают несколько месяцев, и я хочу иметь возможность взять среднее значение за день и разделить его на соответствующие месяцы.Например, скажем, что одна точка данных - это 2/9/2010 - 3/8/2010, а сумма - 1500. Затем запрос должен вернуть 1071,4 для февраля 2010 года и 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;

Ответы [ 3 ]

2 голосов
/ 05 августа 2010

Вы должны выбрать СУММУ и группу с помощью функции МЕСЯЦ (дата) следующим образом:

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

Присоедините таблицу к этой функции, а затем суммируйте по дням

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

GROUP BY M.MonthValue

Я могу немного почистить это, если получу некоторые данные образца

1 голос
/ 06 августа 2010

Это решение обрабатывает [start_date, end_date] интервалы от одного (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_name | month_amount  |
+----+------------+---------------+
|  1 | January    |  187.87878788 | 
|  1 | February   |   12.12121212 | 
|  2 | February   |  250.00000000 | 
|  3 | February   |   81.81818182 | 
...

Мы используем DATEDIFF для определения количества дней, представленных исходной записью.Затем, построив таблицу целых чисел , мы можем перечислить месяц каждого дня в определенном интервале.Отсюда вопрос об агрегации SQL по записям id и month_name.

0 голосов
/ 05 августа 2010

Это отделяет сумму по месяцам:

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

Однако все становится немного сложнее, так как сначала вы должны проверить, если датына самом деле в разные месяцы, и если дата охватывает более двух месяцев, вам нужен другой подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...