2013-09-28 6 views
2

У меня есть одна таблица, которая получает результаты от игры. Каждая игра имеет свой собственный идентификатор и длится всего 7 дней. Один раз в день все игры помещают свои результаты в эту таблицу (результаты для умения A, умения B, ... хранятся в каждой колонке).Как рассчитать разницу между mysql-строками, вид разных

Что мне нужно для восстановления в MySQL: мне нужно отображать каждую игру (game_id) и все ее результаты, а также прогресс между результатами каждого дня (возможно, вверх или вниз).

Что-то, как это должно быть результатом:

Game_id date  result_a progress result_b progress  
1234  2013-09-01 10   0   8   0 
1234  2013-09-02 08   -2   6   -2 
1234  2013-09-03 15   7   10   4 
1234  2013-09-04 19   4   13   3 
4321  2013-09-01 09   0   7   0 
4321  2013-09-02 18   9   9   2 
4321  2013-09-03 15   -3   11   2 
4321  2013-09-04 09   -6   16   4 

Любые советы, как справиться с этой простой (это может стать что-то с около 4000 строк ...)?

http://sqlfiddle.com/#!2/70a96/4

+0

Do вам нужен только оператор SQL, или вы также получаете работу с кодом на стороне сервера? –

+0

Мне интересно, как далеко это можно сделать в MySQL и что я могу получить в PHP для работы с –

ответ

1

Если вы можете работать в PHP, прежде чем совершать это значение в БД, вы можете иметь все значения в течение всей недели, и вы можете перебрать каждые данные, а затем обновить прогресс на основе разницы между текущим и предыдущим, а затем обновить таблицу с новыми значениями прогресса.

Пожалуйста, простите меня за это письмо просто псевдокод, как я м не хорошо на PHP

//Get the values from the Database, only the columns, game_id, date, result_a, result_b 
for(i=0;all values) 
{ 
    progress[i] = result[i]- result[i-1]; 
} 

//finally save the result as you have prgress value for all i's 
+0

Да, я искал в предварительную обработку тоже. Данные поступают из внешнего html-файла b eing обрабатывается и импортируется в базу данных.Это будет ежедневный cronjob, так что это возможно, но на данный момент мы хотели бы попробовать его на выходе ... –

1

После запроса должно привести к выходу требуется (за исключением порядка столбцов). Трюк здесь состоит в том, чтобы проверить, остается ли предыдущий идентификатор игры неизменным (переменная), и если да, то вычитаем с предыдущими данными результата (переменными), чтобы получить результат или просто вернуть 0.

Почему столбец порядок немного другой? Это связано с тем, что в противном случае переменные уже переопределены текущим значением, поэтому в итоге вы получите всегда 0. Вот почему вы должны установить «предыдущие» переменные после сравнения (сравнения) и вычитаний.

SELECT 
    @progress_a := IF(@prevGameId = data.game_id, 
         data.result_a - @prevResultA, 
         0) AS 'progress_a', 
    @prevResultA := data.result_a AS 'result_a', 
    @progress_b := IF(@prevGameId = data.game_id, 
         data.result_b - @prevResultB, 
         0) AS 'progress_b', 
    @prevResultB := data.result_b AS 'result_b', 
    data.registration_date, 
    (@prevGameId := data.game_id) AS 'game_id' 
FROM (SELECT 
      game_id, 
      result_a, 
      result_b, 
      registration_date 
     FROM games 
     ORDER BY game_id, registration_date 
    ) AS data 
JOIN (SELECT 
      @prevGameId := NULL, 
      @prevResultA := NULL, 
      @prevResultB := NULL 
    ) dummy 

Последний JOIN необходим для инициализации переменных (если вы можете запускать только один запрос). В противном случае вы можете использовать инструкции SET для инициализации переменных (перед SELECT).

SELECT внутри FROM необходим, поскольку записи каждой игры не гарантируются сгруппированы. Поэтому я убеждаюсь, что они заказаны вместе и отсортированы по дате регистрации. Преимущество в том, что если вы не можете гарантировать, что каждая дата регистрации (за игру) уникальна, вы можете группировать даже каждую игру/registration_date.

Примечание: если у вас возникли серьезные проблемы с производительностью (не должно быть, я думаю), вам придется либо обработать его в приложении, либо рассчитать прогресс при вставке данных (сохранить данные о ходе выполнения) избыточно).

+0

Это потрясающе. Немного сложнее заглянуть в 2 часа ночи, но он обязательно заполнит мое воскресное утро! Я вернусь к этому с прогрессом, который я ему сделал, поскольку db, конечно, немного сложнее ... –

+0

Он выглядит более сложным, чем на самом деле ;-). Сообщите мне, можете ли вы сделать это в своем проекте, используя указанный выше запрос. – Styxxy

1

Попробуйте - он работал в вашей sqlfiddle

SELECT g.id, g.game_id, g.registration_date as today, y.registration_date as yesterday 
    ,g.result_a as result_a 
    ,COALESCE(g.result_a - y.result_a,0) as progress_a 
    ,g.result_b as result_b 
    ,COALESCE(g.result_b - y.result_b,0) as progress_b 
FROM games g 
LEFT JOIN games y 
    ON g.game_id = y.game_id 
    AND g.registration_date > y.registration_date 
WHERE NOT EXISTS 
    (SELECT * 
    FROM games 
    WHERE games.registration_date > y.registration_date 
    AND games.registration_date < g.registration_date) 
ORDER BY g.game_id, g.registration_date, y.registration_date 

Если даты всегда последовательные (то есть, предыдущая игра всегда вчера, то SQL запрос становится гораздо проще:

SELECT g.id, g.game_id, g.registration_date as today, y.registration_date as yesterday 
    ,g.result_a as result_a 
    ,COALESCE(g.result_a - y.result_a,0) as progress_a 
    ,g.result_b as result_b 
    ,COALESCE(g.result_b - y.result_b,0) as progress_b 
FROM games g 
LEFT JOIN games y 
    ON g.game_id = y.game_id 
    AND DATEDIFF(g.registration_date, y.registration_date) = 1 
ORDER BY g.game_id, g.registration_date, y.registration_date 
Смежные вопросы