MySQL 从历史记录中查询跟踪记录 table

MySQL query to Track records from History table

我需要了解 mysql 查询中的逻辑以跟踪所有更改的历史记录。下面的例子将解释我的期望。

account table

+------+---------+---------------------+---------------------+
| id   | emailid | created_date        | modified_date       |
+------+---------+---------------------+---------------------+
|    1 | abc     | 2020-03-20 00:00:00 | 2020-07-10 00:00:00 |
+------+---------+---------------------+---------------------+

account_history table

+------+---------+---------------------+
| id   | emailid | modified_date       |
+------+---------+---------------------+
|    1 | def     | 2020-04-03 00:00:00 |
|    1 | ghi     | 2020-05-05 00:00:00 |
|    1 | lmn     | 2020-06-05 00:00:00 |
|    1 | opq     | 2020-07-01 00:00:00 |
|    1 | opq     | 2020-07-03 00:00:00 |
|    1 | qrs     | 2020-07-10 00:00:00 |
+------+---------+---------------------+

预期结果

+------+-----------+----------+----------+-------------------+---------------------+
| id   | parameter | oldvalue | newvalue | event             | event_datetime      |
+------+-----------+----------+----------+-------------------+---------------------+
|    1 | emailid   | NULL     | def      | New Entry         | 2020-03-20 00:00:00 |
|    1 | emailid   | def      | ghi      | Change in account | 2020-04-03 00:00:00 |
|    1 | emailid   | ghi      | lmn      | Change in account | 2020-05-05 00:00:00 |
|    1 | emailid   | lmn      | opq      | Change in account | 2020-06-05 00:00:00 |
|    1 | emailid   | opq      | qrs      | Change in account | 2020-07-03 00:00:00 |
|    1 | emailid   | qrs      | abc      | Change in account | 2020-07-10 00:00:00 |
+------+-----------+----------+----------+-------------------+---------------------+

我有主要 table 调用 account 和历史 table 调用 account_history。帐户中的每个更改都将在其历史记录 table 中进行跟踪,当前值将存储在历史记录 table 中。我希望我的输出是这样的。如果没有发生变化,则无需跟踪。我每天都有逻辑要跟踪。但是我想跟踪它以获取过去的数据。 跟踪每日查询,

mysql>  select id,'emailid',acch.emailid as oldvalue,acc.emailid as newvalue,'Change in account',acc.modified_date from account acc join account_history acch using(id) where acc.emailid!=acch.emailid and acc.modified_date=acch.modified_date;
+------+---------+----------+----------+-------------------+---------------------+
| id   | emailid | oldvalue | newvalue | Change in account | modified_date       |
+------+---------+----------+----------+-------------------+---------------------+
|    1 | emailid | qrs      | abc      | Change in account | 2020-07-10 00:00:00 |
+------+---------+----------+----------+-------------------+---------------------+
1 row in set (0.00 sec)

感觉难以追踪过去的数据。帮我解决这个问题。

mysql 版本 14.14 分发 5.7.23

即使超过 1 或 2 个查询来获得解决方案也会有所帮助。通过创建任何中间 tables 并得出解决方案将会有所帮助。

假设我们没有能力优化table结构。因此,主要思想是执行以下操作:

  1. 将初始数据转换为顺序修改列表。
  2. 在新值记录的序号有下一个序号相对于旧值记录的序号的地方加入这个列表。

MySQL5.7 的解决方案为简单起见描述为两阶段查询。这可以在 MySQL 8 中更简单地完成。此外,这不是优雅的解决方案,但易于解释的方法。

步骤 1. 顺序列表。

-- The variable to create sequential number
SET @rn := 0;

SELECT @rn := @rn + 1 as rn,
       ah.*
FROM (
    -- Add history record for creating new entry
    SELECT id, null as emailid, 'New Entry' as event, created_date as modified_date
    FROM account

    UNION
    -- Add intermediate history records
    -- Need grouping to filter identical values (like 'opq')
    SELECT id, emailid, 'Change in account' as event, min(modified_date) as modified_date
    FROM account_history GROUP BY id, emailid

    UNION

    -- Add history record for current value
    SELECT id, emailid, 'Change in account' as event, modified_date
    FROM account
) as ah,
  (SELECT @row := 0) as r

ORDER BY id, modified_date;

此查询产生以下列表:

rn  id  emailid  event              modified_date
 1   1  NULL     New Entry          2020-03-20 00:00:00
 2   1  def      Change in account  2020-04-03 00:00:00
 3   1  ghi      Change in account  2020-05-05 00:00:00
 4   1  lmn      Change in account  2020-06-05 00:00:00
 5   1  opq      Change in account  2020-07-01 00:00:00
 6   1  qrs      Change in account  2020-07-10 00:00:00
 7   1  abc      Change in account  2020-07-10 00:00:00

步骤 2. 自连接顺序列表。

假设上面的列表被命名为 subquery(子查询、视图、临时 table 等)。通过以下方式加入:

SELECT s1.id,
       'emailid' as emailid,
       s1.emailid as oldvalue,
       s2.emailid as newvalue,
       s1.event,
       s1.modified_date
FROM subquery as s1
    JOIN subquery as s2
        ON s2.id = s1.id AND s2.rn = s1.rn + 1