MySQL - найти разницу между строками одной таблицы - PullRequest
6 голосов
/ 23 марта 2011

У меня есть таблица, содержащая агрегированные результаты с временными метками. Это означает, что каждый результат за время является общим:

date       | time  | ip       | result
---------------------------------------
2011-03-01 | 10:00 | 10.0.0.1 | 200
2011-03-01 | 11:00 | 10.0.0.1 | 303
2011-03-01 | 12:00 | 10.0.0.1 | 415
2011-03-01 | 13:00 | 10.0.0.1 | 628
2011-03-01 | 10:00 | 10.0.0.2 | 198
2011-03-01 | 11:00 | 10.0.0.2 | 234
2011-03-01 | 12:00 | 10.0.0.2 | 373
2011-03-01 | 13:00 | 10.0.0.2 | 512

Я пытаюсь сформулировать запрос, который будет получать дельты между каждым разомдиапазон:

date       | time  | ip       | diff
---------------------------------------
2011-03-01 | 10:00 | 10.0.0.1 | 200
2011-03-01 | 11:00 | 10.0.0.1 | 103
2011-03-01 | 12:00 | 10.0.0.1 | 112
2011-03-01 | 13:00 | 10.0.0.1 | 213
2011-03-01 | 10:00 | 10.0.0.2 | 198
2011-03-01 | 11:00 | 10.0.0.2 |  36
2011-03-01 | 12:00 | 10.0.0.2 | 139
2011-03-01 | 13:00 | 10.0.0.2 | 139
...

Таким образом, каждая строка в каждой дате / группе ip вычитает одну перед ней (или 0).Есть ли простой способ сделать это?спасибо.

Ответы [ 2 ]

10 голосов
/ 23 марта 2011

Вот решение без переменных.Я предполагаю, что у вас есть данные initail в таблице с именем thetable.

SELECT date, time, ip,
    result - IFNULL( (
        SELECT MAX( result ) 
        FROM thetable
        WHERE ip = t1.ip
        AND ( date < t1.date
            OR date = t1.date AND time < t1.time )
    ) , 0) AS diff
FROM thetable AS t1
ORDER BY ip, date, time

Здесь мы получаем предыдущее значение с подвыбором (максимальное result из предыдущих отметок времени из того же ip),IFNULL дает нам 0, если это было первое значение, поэтому начальные результаты отображаются правильно.

Я также рекомендую добавить следующий индекс к thetable:

CREATE INDEX sort1 ON thetable (ip, date, time);
4 голосов
/ 23 марта 2011

Попробуйте это -

SET @f_rank = 0;
SET @s_rank = 0;
SET @f_date = NULL;
SET @f_ip = NULL;
SET @s_date = NULL;
SET @s_ip = NULL;
SELECT t1.date, t1.time, t1.ip, IF(t2.result IS NULL, t1.result, t1.result - t2.result) diff FROM
    (SELECT *, IF(@f_date = date AND @f_ip = ip, @f_rank:=@f_rank + 1, @f_rank:=1) AS rank, @f_date := date, @f_ip := ip FROM table1 ORDER BY date, ip, time) t1
  LEFT JOIN 
    (SELECT *, IF(@s_date = date AND @s_ip = ip, @s_rank:=@s_rank + 1, @s_rank:=1) AS rank, @s_date := date, @s_ip := ip FROM table1 ORDER BY date, ip, time) t2
  ON t1.date = t2.date AND t1.ip = t2.ip AND (t1.rank = t2.rank + 1);

+------------+----------+----------+------+
| date       | time     | ip       | diff |
+------------+----------+----------+------+
| 2011-03-01 | 10:00:00 | 10.0.0.1 |  200 |
| 2011-03-01 | 11:00:00 | 10.0.0.1 |  103 |
| 2011-03-01 | 12:00:00 | 10.0.0.1 |  112 |
| 2011-03-01 | 13:00:00 | 10.0.0.1 |  213 |
| 2011-03-01 | 10:00:00 | 10.0.0.2 |  198 |
| 2011-03-01 | 11:00:00 | 10.0.0.2 |   36 |
| 2011-03-01 | 12:00:00 | 10.0.0.2 |  139 |
| 2011-03-01 | 13:00:00 | 10.0.0.2 |  139 |
+------------+----------+----------+------+
...