选择每行的值已更改的列

问题描述 投票:-1回答:1

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

让我说我有这张桌子。

表A

+--------+----+-------+-------+-------+---------+
|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 |
+--------+----+-------+-------+-------+---------+

我有多个表和不同数量的列和项目。我不介意硬编码表名和列名。

我想最终得到这张桌子

+----+------+-------+--------+-------------+---------+
|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   |
+----+------+-------+--------+-------------+---------+
mysql sql
1个回答
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;
© www.soinside.com 2019 - 2024. All rights reserved.