2

我有一张从游戏中接收结果的表。每个游戏都有自己的 ID,并且只持续 7 天。每天一次,所有游戏将其结果放入此表中(技能 A、技能 B、...的结果分别存储在一个列中)。

我需要能够在 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

4

3 回答 3

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
于 2013-09-29T11:26:56.473 回答
1

以下查询应产生您想要的输出(列的顺序除外)。这里的技巧是检查之前的游戏 id 是否仍然相同(变量),如果是,则与之前的结果数据(变量)相减以获得结果,否则只返回 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 是初始化变量所必需的(如果您只能触发 1 个查询)。否则,您可以使用 SET 语句来初始化变量(在 SELECT 之前)。

FROM 中的 SELECT 是必要的,因为不能保证对每场比赛的记录进行分组。所以我确保它们是一起订购的,并在注册日期排序。优点是,如果您不能保证每个注册日期(每个游戏)都是唯一的,那么您甚至可以对每个游戏/注册日期进行分组。

注意:如果您遇到严重的性能问题(我认为不应该),您确实必须在应用程序中处理它或在插入数据时计算进度(冗余存储“进度”数据)。

于 2013-09-28T23:22:09.873 回答
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
于 2013-09-28T22:44:17.520 回答