使用交叉应用将列转置为行

transpose columns to row using cross apply

源数据

+--------+-------+---------------+------------+--------+--------------+-------+
| RowNum | SeqNo |     Name      | NameReason | Gender | GenderReason |  ID   |
+--------+-------+---------------+------------+--------+--------------+-------+
|      1 | A123  | IronMan       |            | P      |              | E8888 |
|      2 | A123  | CaptainMarvel | A          | L      | A            | E8888 |
|      3 | A123  | Yoooo         |            |        |              | E8888 |
|      4 | A123  | Heyyy         |            |        |              | E8888 |
|      1 | B456  | Hey           |            |        |              | D2222 |
|      2 | B456  | DOTS          | A          |        |              | D2222 |
|      1 | C1234 | Hulk          |            |        |              | E8989 |
|      2 | C1234 | Cap           |            |        |              | E8989 |
|      3 | C1234 | Hat           |            |        |              | E8989 |
+--------+-------+---------------+------------+--------+--------------+-------+

我想要的结果

+-------+-------+---------+---------------+----------+--------+
| SeqNo |  ID   | ColName |  From_Value   | To_Value | Reason |
+-------+-------+---------+---------------+----------+--------+
| A123  | E8888 | Name    | CaptainMarvel | IronMan  | A      |
| A123  | E8888 | Gender  | L             | P        | A      |
| B456  | D2222 | Name    | DOTS          | Hey      | A      |
| C1234 | E8989 | Name    | Cap           | Hulk     |        |
+-------+-------+---------+---------------+----------+--------+

查询:

select a.rownum, a.seqno, a.name, a.id,
       b.*
from #A a cross apply
( values ('Name', NameReason)
         ('Gender', GenderReason)
    ) b (colname, Reason)
where reason is not null

注:要查找修改。 RowNum=1是最新更新(To_Value),RowNum=2From_Value)。 Rownum 已经过滤了顶部更新的结果 (rownumber () over (partitition)我只需要rownum=2(from_Value),rownum=1(to_value)其他忽略,因为1个应用可以更新100次,我只需要找到最新的更改即可。

从上面的查询中,如何修改为我想要的结果?如何添加 from_value 和 to_value,原因?

您可以使用 UNION.

编写查询,如下所示
  select t1.SeqNo, 
       t1.Name, 
       t1.ID, 
       'Name'                  as ColName, 
       (select name 
        from   mytable mt 
        where  mt.SeqNo = t1.seqNo 
               and RowNum = 2) as From_Value, 
       t1.Name                 as To_Value 
from   mytable t1 
where  t1.RowNum = 1 
union all
select * 
from   (select t1.SeqNo, 
               t1.Name, 
               t1.ID, 
               'Gender'                as ColName, 
               t1.Gender               as From_Value, 
               (select Gender 
                from   mytable mt 
                where  mt.SeqNo = t1.seqNo 
                       and RowNum = 1) as To_Value 
        from   mytable t1 
        where  t1.RowNum = 2) t 
where  From_Value is not null 

Online Demo

输出

+-------+---------------+-------+---------+---------------+----------+
| SeqNo | Name          | ID    | ColName | From_Value    | To_Value |
+-------+---------------+-------+---------+---------------+----------+
| A123  | CaptainMarvel | E8888 | Gender  | L             | P       |
+-------+---------------+-------+---------+---------------+----------+
| A123  | IronMan       | E8888 | Name    | CaptainMarvel | IronMan  |
+-------+---------------+-------+---------+---------------+----------+
| B456  | Hey           | D2222 | Name    | DOTS          | Hey      |
+-------+---------------+-------+---------+---------------+----------+

假设你可以link RowNum + 1

上的"From"记录
SELECT q.SeqNo, q.ToName AS Name, q.ID, ca.ColName, ca.From_Value, ca.To_Value 
FROM
(
  SELECT 
   a1.ID, a1.SeqNo, a1.NameReason, a1.GenderReason, a1.RowNum, 
   a2.Name as FromName, a1.Name as ToName,
   a2.Gender AS FromGender, a1.Gender AS ToGender
  FROM #A a1
  JOIN #A a2 ON (a2.ID = a1.ID AND a2.RowNum = a1.RowNum + 1)
  WHERE (a1.NameReason IS NOT NULL OR a1.GenderReason IS NOT NULL)
    AND a1.Name != a2.Name
) q
CROSS APPLY (VALUES 
 (1, 'Name', NameReason, FromName, ToName), 
 (2, 'Gender', GenderReason, FromGender, ToGender)
) ca (ColSeq, ColName, Reason, From_Value, To_Value)
WHERE ca.Reason IS NOT NULL
ORDER BY q.SeqNo, ca.ColSeq;

但根据评论,只有 RowNum 1 和 2 重要。
然后就可以简化了。

SELECT q.SeqNo, q.ToName AS Name, q.ID, ca.ColName, ca.From_Value, ca.To_Value 
FROM
(
  SELECT 
   a1.ID, a1.SeqNo, 
   a1.NameReason, a2.Name as FromName, a1.Name as ToName,
   a1.GenderReason, a2.Gender AS FromGender, a1.Gender AS ToGender
  FROM #A a1
  JOIN #A a2 ON (a2.ID = a1.ID AND a2.RowNum = 2)
  WHERE a1.RowNum = 1
) q
CROSS APPLY (VALUES 
 (1, 'Name', NameReason, FromName, ToName), 
 (2, 'Gender', GenderReason, FromGender, ToGender)
) ca (ColSeq, ColName, Reason, From_Value, To_Value)
WHERE ca.Reason IS NOT NULL
ORDER BY q.SeqNo, ca.ColSeq;

结果:

SeqNo Name    ID    ColName From_Value    To_Value
----- ------- ----- ------- ------------- --------
A123  IronMan E8888 Name    CaptainMarvel IronMan
A123  IronMan E8888 Gender  L             P
B456  Hey     D2222 Name    DOTS          Hey

db<>fiddle here

的测试