选择其中每一行的值已更改的列

时间:2018-11-27 21:27:58

标签: mysql sql

我正在尝试从MySQL表中提取数据并以一种日志文件格式插入到另一个表中。

说我有这张桌子。

TableA

+--------+----+-------+-------+-------+---------+
|UniqueID|Item|ColumnA|ColumnB|ColumnC|TimeStamp|
+--------+----+-------+-------+-------+---------+
|1       | 1  | 500   | 600   | 700   |   13:01 |
|2       | 2  |  50   |  60   |  70   |   13:03 |
|3       | 3  |  17   |  18   |  19   |   13:12 |
|4       | 1  | 501   | 600   | 700   |   13:15 |
|5       | 1  | 501   | 600   | 699   |   13:18 |
|6       | 3  |  20   |  18   |  19   |   13:22 |
|7       | 1  | 501   | 600   | 702   |   13:25 |
|8       | 2  |  50   |  66   |  70   |   13:26 |
|9       | 3  |  20   |  25   |  19   |   13:32 |
+--------+----+-------+-------+-------+---------+

会有多个表,其中包含不同数量的列和项目。 我不介意对表名和列名进行硬编码。

Id希望以该表结尾

+----+------+-------+--------+-------------+---------+
|Item|Table |Column |NewValue|PreviousValue|TimeStamp|
+----+------+-------+--------+-------------+---------+
| 1  |TableA|ColumnA| 501    | 500         | 13:15   |
| 1  |TableA|ColumnC| 699    | 700         | 13:18   |
| 3  |TableA|ColumnA|  20    |  17         | 13:22   |
| 1  |TableA|ColumnC| 699    | 702         | 13:25   |
| 2  |TableA|ColumnB|  66    |  60         | 13:26   |
| 3  |TableA|ColumnB|  25    |  18         | 13:32   |
+----+------+-------+--------+-------------+---------+

1 个答案:

答案 0 :(得分:1)

MySQL并没有使它变得如此简单。您可以通过计算先前的时间戳然后将其加入来获得先前的记录。在MySQL 8.0中,您可以为此使用lag()

然后,您需要取消旋转值。 MySQL确实没有做到这一点,但是您可以使用cross joincase表达式。其余的只是条件逻辑和过滤:

select item, 'TableA' as tableName, colname,
       col as newvalue, col_prev as prevvalue, timestamp
from (select t.*, c.colname,
             (case when c.colname = 'columnA' then columnA
                   when c.colname = 'columnB' then columnB
                   when c.colname = 'columnC' then columnC
              end) as col,
             (case when c.colname = 'columnA' then tprev.columnA
                   when c.colname = 'columnB' then tprev.columnB
                   when c.colname = 'columnC' then tprev.columnC
              end) as col_prev
      from (select t.*,
                   (select max(t2.timestamp)
                    from tablea t2
                    where t2.item = t.item and t2.timestamp < t.timestamp
                   ) as timestamp_prev
            from tablea t
           ) t join
           t tprev
           on t.item = tprev.item and t.timestamp_prev = tprev.timestamp cross join
           (select 'columnA' as colname union all
            select 'columnB' as colname union all
            select 'columnC' as colname
           ) c
     ) ct
where col_prev <> col;