mysql:从临时表聚合多个对象的更改

rjzwgtxy  于 2021-06-23  发布在  Mysql
关注(0)|答案(1)|浏览(363)

我有一个这样的表,其中保存了每个角色的每个状态更改。

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。

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

更糟的是,table `characters_changes` 是一张临时table。其中的datetime来自另一个事件表。因为它是临时的,所以我只能查询一次。但是可以有任意数量的字符,而且很可能会有更多的列,比如rank和job。
整个系统需要提供这样一种可能性,即通过忽略在给定日期时间之后的所有更改来获取所有字符的状态。但这一部分对我来说很容易,所以我把它排除在我的问题范围之外。
5sxhfpxr

5sxhfpxr1#

我认为这应该管用:

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

相关问题