MySQL:来自临时表

时间:2018-06-07 18:00:55

标签: mysql aggregate temporary

我有一个这样的表格,每个角色的每个状态都会被保存。

table characters_changes
+----+--------+---------+-------+----------------------+
| id |  rank  |   job   | money |      datetime        |
+----+--------+---------+-------+----------------------+
| 1  |   2    | tailor  |  25   | 2018-06-01 12:30:15  |
| 1  |   3    |  NULL   |   5   | 2018-06-02 10:50:19  |
| 1  |   2    |  NULL   |  -5   | 2018-06-03 18:44:35  |
| 1  |  NULL  | tinker  |  10   | 2018-06-04 04:10:12  |
| 1  |   3    |  NULL   | NULL  | 2018-06-05 17:31:00  |
|  2 |    1   |   spy   |   7   |  2018-06-01 12:30:15 |
|  2 |    2   |   NULL  |  NULL |  2018-06-02 10:50:19 |
|  2 |   NULL |  no job |   7   |  2018-06-03 17:31:00 |
| 3  |   3    | soldier |  12   | 2018-06-01 12:30:15  |
| 3  |   1    |  NULL   | -11   | 2018-06-02 10:50:19  |
+----+--------+---------+-------+----------------------+

NULL表示相应属性没有变化。 等级和工作变化意味着替换另一个, 货币变动意味着增加和减去总和(如果不是NULL)。每个字符至少保留一行,没有任何NULL - s。

所以我需要得到一张表格,我可以在最后显示每个角色的当前状态。 他们的最后一个职位,最后的工作和由此产生的金额。像这样的表。

table characters_status
+----+--------+---------+-------+
| id |  rank  |   job   | money |
+----+--------+---------+-------+
| 1  |   3    | tinker  |  35   |
|  2 |    2   |  no job |   14  |
| 3  |   1    | soldier |   1   |
+----+--------+---------+-------+

更糟糕的是,表characters_changes是一个临时表。 其中的日期时间来自另一个事件表。 因为它是临时的,我只能查询一次。但是可以有任意数量的角色,并且很可能会有更多的列,如排名和工作。

需要整个系统通过忽略之后的所有更改来提供在任何给定日期时间获取所有字符的状态的可能性。但这部分对我来说很容易,所以我把它排除在我的问题范围之外。

1 个答案:

答案 0 :(得分:0)

这应该有效,我想:

SELECT id
   , CASE WHEN INSTR(ranks, '|') = 0 THEN ranks ELSE LEFT(ranks, INSTR(ranks, '|')-1) END AS rank
   , CASE WHEN INSTR(jobs, '|') = 0 THEN jobs ELSE LEFT(jobs, INSTR(jobs, '|')-1) END AS job
   , monies
FROM
(
   SELECT id
      , GROUP_CONCAT(rank ORDER BY datetime DESC SEPARATOR '|') AS ranks
      , GROUP_CONCAT(job ORDER BY datetime DESC SEPARATOR '|') AS jobs
      , SUM(money) AS monies
   FROM characters_changes
   GROUP BY id
) AS lists
;

从技术上讲,你可以在没有子查询的情况下完成它,但为了清楚起见,我将其分解为这种方式。替代方案是这样的表达式:

, CASE COUNT(rank) WHEN 0 THEN NULL WHEN 1 THEN GROUP_CONCAT(rank ORDER BY datetime DESC SEPARATOR '|') ELSE LEFT(GROUP_CONCAT(rank ORDER BY datetime DESC SEPARATOR '|'), INSTR(GROUP_CONCAT(rank ORDER BY datetime DESC SEPARATOR '|'), '|')-1) END AS rank