SQL :列出行之间的差异(显示在列中)

SQL : list differences between rows (showed in columns)

我有一个table这样的

ID   |  FatherID     |   A   |  B    |   C   |     D        | ...
1234 |     -1        |  John | Doe   |   15  |   20181211   | ...
5678 |     -1        |  Mark | Bloch |   34  |   20170804   | ...
4554 |     1234      |  John | Dee   |   25  |   20181211   | ...
2457 |     5678      |  Chris| Bloch |   34  |   20180402   | ...

如果对给定对象(例如 ID 1234)进行了修改,系统会将新版本数据存储在新 ID(例如 4554)上,并引用原始 ID(FatherID = 1234)。 系统只存储初始版本和 head revision(最后修改),例如如果 4554 最终再次修改,则不会创建新记录但会更新 4554 值 --> Max 2 records per ID

有很多列(大约 400)...

我想以这样的格式列出已完成的修改:

ID   | Field | Before       | After
4554 |  B    | Doe          | Dee
4554 |  C    | 15           | 25
2457 |  A    | Mark         | Chris
4554 |  D    | 20170804     | 20180402

我正在努力做到这一点,尤其是考虑到列数。

如有任何帮助,我们将不胜感激!

非常感谢

There are lots of columns (around 400) ...

只是为了让您了解仅检查 4 列的情况(这是针对 Oracle):

WITH full AS (
  SELECT 
    o.ID, 
    o.A, o.B, o.C, o.D, 
    n.A AS newA, n.B AS newB, n.C AS newC, n.D AS newD 
  FROM tablename o 
  INNER JOIN tablename n ON n.FatherID = o.ID
  WHERE o.FatherID = -1
)

SELECT ID, Field, Before, After FROM(
  SELECT 
    ID,
    'A' As Field,
    CASE WHEN A <> newA THEN 1 ELSE 0 END AS changed,
    A AS Before,
    newA AS After
  FROM full
  UNION
  SELECT 
    ID,
    'B' As Field,
    CASE WHEN B <> newB THEN 1 ELSE 0 END AS changed,
    B AS Before,
    newB AS After
  FROM full
  UNION
  SELECT 
    ID,
    'C' As Field,
    CASE WHEN C <> newC THEN 1 ELSE 0 END AS changed,
    C AS Before,
    newC AS After
  FROM full
  UNION
  SELECT 
    ID,
    'D' As Field,
    CASE WHEN D <> newD THEN 1 ELSE 0 END AS changed,
    D AS Before,
    newD AS After
  FROM full
)  
WHERE changed = 1

您可以逆透视成对的列并仅过滤不同的列。

select id, fatherid, field, o before, n after 
  from (
    select n.id, n.fatherid, n.a na, o.a oa, n.b nb, o.b ob, 
           to_char(n.c) nc, to_char(o.c) oc, 
           to_char(n.d) nd, to_char(o.d) od
      from t n join t o on n.fatherid = o.id)
  unpivot ((n, o) for field in ((na, oa) as 'A', (nb, ob) as 'B', 
                                (nc, oc) as 'C', (nd, od) as 'D'))
  where n <> o or (n is null and o is not null) or (n is not null and o is null)
  order by id, field

demo with your sample data

    ID   FATHERID  FIELD  BEFORE    AFTER
------  ---------  -----  --------  -----------
  2457       5678  A      Mark      Chris
  2457       5678  D      20170804  20180402
  4554       1234  B      Doe       Dee
  4554       1234  C      15        25

您必须列出所有列,将它们转换为字符。很多工作,很多 space 的错误,但这是我想到的最好的。