如何确定数据库记录之间的变化

时间:2018-02-12 22:07:02

标签: mysql database

首先假设MySQL数据库中存在以下表

|----|-----|-----|----|----|-----------|--------------|----|
| id | rid | ver | n1 | n2 | s1        | s2           | b1 |
|----|-----|-----|----|----|-----------|--------------|----|
| 1  | 1   | 1   | 0  | 1  | Hello     | World        | 0  |
| 2  | 1   | 2   | 1  | 1  | Hello     | World        | 0  |
| 3  | 1   | 3   | 0  | 0  | Goodbye   | Cruel World  | 0  |
| 4  | 2   | 1   | 0  | 0  | Hello     | Doctor       | 1  | 
| 5  | 2   | 2   | 0  | 0  | Hello     | Nurse        | 1  |
| 6  | 3   | 1   | 0  | 0  | Dippity   | Doo-Dah      | 1  |
|----|-----|-----|----|----|-----------|--------------|----|

问题

如何编写查询以确定是否对于任何给定的rid,最新版本和紧接在它之前的版本(如果有)之间发生了什么变化,以便它产生如下内容:

|-----|-----------------|-----------------|-----------------|
| rid | numbers_changed | strings_changed | boolean_changed |
|-----|-----------------|-----------------|-----------------|
| 1   | TRUE            | TRUE            | FALSE           |
| 2   | FALSE           | TRUE            | FALSE           |
| 3   | n/a             | n/a             | n/a             |
|-----|-----------------|-----------------|-----------------|

我认为我应该能够通过在表和它自身之间进行交叉连接来实现这一点,但我无法解决如何执行此连接以获得所需的输出。

我需要为包含10列和1-10个记录的1-10个版本的表生成此“报告”(产生1000行)。请注意,数据库的特定设计不是我自己的,并且更改数据库的结构(此时)不是一种可接受的方法。

输出的实际格式并不重要 - 如果它简化了查询,那么对每个“更改集”的更改进行“完全分解”也是可以接受的,例如

|-----|-----|-----|----|----|----|----|----|
| rid | old | new | n1 | n2 | s1 | s2 | b1 |
|-----|-----|-----|----|----|----|----|----|
| 1   | 1   | 2   | Y  | N  | N  | N  | N  |
| 1   | 2   | 3   | Y  | Y  | Y  | Y  | N  |
| 2   | 4   | 5   | N  | N  | N  | Y  | N  |
|-----|-----|-----|----|----|----|----|----|

请注意,它也可以,在这种情况下省略只有一个版本的rid记录,因为本报告的目的我只关心已更改的记录并获取单独的记录列表没有改变是一个简单的查询

1 个答案:

答案 0 :(得分:2)

您可以使用

加入每一行
select *
from history h1
join history h2
  on  h2.rid = h1.rid
  and h2.id = (
    select min(h.id)
    from history h
    where h.rid = h1.rid
      and h.id > h1.id
  );

然后您只需比较h1.n1 <> h2.n1 as n1等两行中的每一列。

完整查询将是:

select h1.rid, h1.id as old, h2.id as new
  , h1.n1 <> h2.n1 as n1
  , h1.n2 <> h2.n2 as n2
  , h1.s1 <> h2.s1 as s1
  , h1.s2 <> h2.s2 as s2
  , h1.b1 <> h2.b1 as b1
from history h1
join history h2
  on  h2.rid = h1.rid
  and h2.id = (
    select min(h.id)
    from history h
    where h.rid = h1.rid
      and h.id > h1.id
  );

结果:

| rid | old | new | n1 | n2 | s1 | s2 | b1 |
|-----|-----|-----|----|----|----|----|----|
|   1 |   1 |   2 |  1 |  0 |  0 |  0 |  0 |
|   1 |   2 |   3 |  1 |  1 |  1 |  1 |  0 |
|   2 |   4 |   5 |  0 |  0 |  0 |  1 |  0 |

演示:http://sqlfiddle.com/#!9/2e5d12/5

如果列可以包含NULL,则可能需要NOT h1.n1 <=> h2.n1 as n1之类的内容。 <=>是NULL保存等式检查。

如果rid组中的版本保证是连续的,您可以将JOIN简化为

from history h1
join history h2
  on  h2.rid = h1.rid
  and h2.ver = h1.ver + 1

演示:http://sqlfiddle.com/#!9/2e5d12/7