Вот альтернатива, которая использует только одно соединение.
DECLARE @RowData TABLE(RowNum INT, SeqNo VARCHAR(10), Col1Before VARCHAR(10), Col1After VARCHAR(10), Col2Before VARCHAR(10), Col2After VARCHAR(10), Col3Before VARCHAR(10), Col3After VARCHAR(10))
INSERT INTO @RowData
VALUES
(1, 'A123', 'A', '', '', '', 'Z', ''),
(2, 'A123', '', 'B', '', '', '', 'D'),
(1, 'B123', '', '', 'C', '', '', ''),
(2, 'B123', '', '', '', 'D', '', ''),
(1, 'C123', 'A', '', 'B', '', '', ''),
(2, 'C123', '', 'A', '', 'B', '', 'A')
SELECT
ColumnChange.SeqNo
,ColumnChange.BeforeValue
,ColumnChange.AfterValue
FROM
@RowData AS BeforeRow
INNER JOIN @RowData AS AfterRow
ON BeforeRow.SeqNo = AfterRow.SeqNo
AND BeforeRow.RowNum = 1
AND AfterRow.RowNum = 2
CROSS APPLY(
SELECT
SeqNo
,TableColumn
,BeforeValue
,AfterValue
FROM
(VALUES
(BeforeRow.SeqNo, 'Col1', BeforeRow.Col1Before, AfterRow.Col1After),
(BeforeRow.SeqNo, 'Col2', BeforeRow.Col2Before, AfterRow.Col2After),
(BeforeRow.SeqNo, 'Col3', BeforeRow.Col3Before, AfterRow.Col3After)
) AS ColumnChange(SeqNo, TableColumn, BeforeValue, AfterValue)
WHERE
ColumnChange.BeforeValue IS NULL AND ColumnChange.AfterValue IS NOT NULL
OR ColumnChange.BeforeValue IS NOT NULL AND ColumnChange.AfterValue IS NULL
OR ColumnChange.BeforeValue != ColumnChange.AfterValue
) AS ColumnChange