MySQL Как суммировать строки в диапазоне временных отметок? - PullRequest
2 голосов
/ 27 июля 2011

Учитывая таблицу со столбцом метки времени, например:

    timestamp           |  id  |  value  
    --------------------------------------
    2001-01-01 00:00:00 |  1   |  3
    2001-01-01 00:00:00 |  2   |  5
    --------------------------------------
    2001-01-02 00:00:00 |  1   |  6
    2001-01-02 00:00:00 |  2   |  10
    2001-01-02 00:00:00 |  3   |  7
    --------------------------------------
    2001-01-03 00:00:00 |  3   |  14
    2001-01-03 00:00:00 |  2   |  15
    --------------------------------------
    2001-01-03 00:00:00 |  1   |  9
    2001-01-03 00:00:00 |  2   |  20

и заданный уровень агрегации, скажем 2 дня , я хотел бы агрегировать (суммировать) результаты по:

(1) подвижное окно заданного уровня агг, для приведенного выше примера: с 2001-01-01 по 2001-01-02, с 2001-01-02 по 2001-01-03, 2001-С 01-03 по 2001-01-04, что приведет к:

    timestamp_1         | timestamp_2         |  id  |  agg_value  
    -----------------------------------------------------------
    2001-01-01 00:00:00 | 2001-01-02 00:00:00 |  1   |  9 (=3+6)
    2001-01-01 00:00:00 | 2001-01-02 00:00:00 |  2   |  15 (=5+10)
    2001-01-01 00:00:00 | 2001-01-02 00:00:00 |  3   |  7 (=7)
    -----------------------------------------------------------
    2001-01-02 00:00:00 | 2001-01-03 00:00:00 |  1   |  6 (=6)
    2001-01-02 00:00:00 | 2001-01-03 00:00:00 |  2   |  25 (=10+15)
    2001-01-02 00:00:00 | 2001-01-03 00:00:00 |  3   |  21 (=7+14)
    -----------------------------------------------------------
    2001-01-03 00:00:00 | 2001-01-04 00:00:00 |  1   |  9 (=9)
    2001-01-03 00:00:00 | 2001-01-04 00:00:00 |  2   |  35 (=15+20)
    2001-01-03 00:00:00 | 2001-01-04 00:00:00 |  3   |  14 (=14)

(2) непересекающемуся делению в заданном диапазоне, для приведенного выше примера: с 2001-01-01 по 2001-01-02, С 2001-01-03 по 2001-01-04, что приведет к:

    timestamp_1         | timestamp_2         |  id  |  agg_value  
    -----------------------------------------------------------

    2001-01-01 00:00:00 | 2001-01-02 00:00:00 |  1   |  9 (=3+6)
    2001-01-01 00:00:00 | 2001-01-02 00:00:00 |  2   |  15 (=5+10)
    2001-01-01 00:00:00 | 2001-01-02 00:00:00 |  3   |  7 (=7)
    -----------------------------------------------------------
    2001-01-03 00:00:00 | 2001-01-04 00:00:00 |  1   |  9 (=9)
    2001-01-03 00:00:00 | 2001-01-04 00:00:00 |  2   |  35 (=15+20)
    2001-01-03 00:00:00 | 2001-01-04 00:00:00 |  3   |  14 (=14)

(что в основном похоже на (1) без перекрытия)

Спасибо!


Отредактировано: добавление решения

У меня есть решение по крайней мере для (1):

    SELECT t1.timestamp AS timestamp1,
    MAX(t2.timestamp) AS timestamp2, t1.id,
    SUM(t2.value) AS agg_value
    FROM my_table t1
    LEFT JOIN my_table t2 ON
    (t2.timestamp >= t1.timestamp AND
    t2.timestamp <= ADDDATE(t1.timestamp,INTERVAL 2 DAY) AND
    t2.id = t1.id)
    GROUP BY t1.timestamp, t1.id

Решением для (2) может быть просто фильтрация кподмножество вышеперечисленного.

1 Ответ

0 голосов
/ 27 июля 2011

Это будет группировать каждые X дней, получая часть даты и получая разницу дат и группируя по разнице дней, плюс ID. Это даст вам решение №2

select 
       CEILING( datediff( date( now() ), date( myTimeStamp )) / 2 ) DaysDiff,
       ID,
       min( date( myTimeStamp )) as FirstDateInGroup,
       max( date( myTimeStamp )) as LastDateInGroup,
       sum( value ) as SumVal
   FROM TimeSample
   group by DaysDiff, ID
   order by FirstDateInGroup, ID

РЕДАКТИРОВАТЬ ---- В КОММЕНТАРИИ

Ваш образец показывал, как обрабатывать в течение 2 дней ... так же и это. «Now ()» - это просто базовая линия для группировки ваших данных. Если вы хотите, чтобы он был разбит по годам, я бы просто сделал запрос на основе ГОДА (YourDateColumn) в качестве группы. Если вы хотите 30 дней, просто разделите на 30. Ежемесячно, я бы сгруппировал по годам (YourDateColumn) и месяцам (YourDateColumn) соответственно. Имея фиксированный диапазон now (), он ничего не делает, только возвращает число в качестве отправной точки. Если вашим данным было 2 года, разница в датах составила бы 365 дней * 2 года = 730 дней ... Разделите на 2, и ваша спина на основе группы составляет 365. Вы можете бросить любое условие where, которое вы хотите, чтобы дополнительно ограничить время период, который вас интересует ...

где myTimeStamp между '2011-01-01' и '2011-06-30' получит только первые 6 месяцев этого года ... Это приведет к тому, что ваша группировка DaysDiff составит 208 дней / 2 = 104.

Таким образом, если у вас есть какое-то другое базовое значение, которое вы хотите создать для своих группировок, вы можете просто изменить now () на что-то вроде «2011-01-01», и оно будет вычисляться на основе 1 января 2011 года. Из них это ничего не даст, кроме как вычислить DaysDiff до отрицательных значений до нуля, а затем до положительных значений.

...