Вы можете попробовать следующее как есть , используя удобный DISTINCT предикат (начиная с Db2 11.1). Эквивалентные выражения могут использоваться для более ранних версий, но они немного длиннее.
WITH
A (ID, C1, C2) AS
(
VALUES
(1, '=', '=')
, (2, '=', '=')
, (4, 'A', '=')
, (5, '=', NULL)
, (6, 'A', 'A')
)
, B (ID, C1, C2) AS
(
VALUES
(1, '=', '=')
, (3, '=', '=')
, (4, 'B', '=')
, (5, '=', NULL)
, (6, 'B', 'B')
)
SELECT
COALESCE(A.ID, B.ID) AS ID
, CASE
WHEN A.ID IS NULL THEN '-A'
WHEN B.ID IS NULL THEN '-B'
ELSE ''
END
|| CASE WHEN A.ID = B.ID AND A.C1 IS DISTINCT FROM B.C1 THEN ', C1' ELSE '' END
|| CASE WHEN A.ID = B.ID AND A.C2 IS DISTINCT FROM B.C2 THEN ', C2' ELSE '' END
--...
--|| CASE WHEN A.ID = B.ID AND A.C60 IS DISTINCT FROM B.C60 THEN ', C60' ELSE '' END
AS FLAG
FROM A
FULL JOIN B ON B.ID = A.ID
WHERE
A.ID IS DISTINCT FROM A.ID
OR A.C1 IS DISTINCT FROM B.C1
OR A.C2 IS DISTINCT FROM B.C2
--...
--OR A.C60 IS DISTINCT FROM B.C60;
Результат:
|ID |FLAG |
|-----------|----------|
|4 |, C1 |
|6 |, C1, C2 |
|3 |-A |
|2 |-B |
Мы используем FULL OUTER JOIN
между двумя таблицами со следующими ИЛИ условия:
- КЛЮЧ (
ID
) равен ПУСТО (NULL) только для одной из этих таблиц (в этой таблице нет совпадений по этому КЛЮЧУ) - Существует разница в одном из соответствующих значений столбца
В столбце FLAG
указан тип разницы:
-TABNAME
- отсутствие ключа в таблице TABNAME
, Cx
- существует разница в столбце Cx
- для каждого такого столбца
Если в обеих таблицах имеется большое количество столбцов, вы можете сгенерируйте соответствующие выражения для этого оператора SELECT
, используя несколько системных представлений Db2.
Например, если мы хотим сгенерировать такие выражения для таблицы SYSIBM.SYSTABLES
, используя один из ее уникальных индексов (вы должны выбрать такой Индекс, предпочтительно одна поддержка ng первичный ключ), затем запустите его как есть, чтобы проверить:
SELECT
'|| CASE WHEN ' || I.KEY_EXPR || ' AND A.' || C.COLNAME || ' IS DISTINCT FROM B.' || C.COLNAME || ' THEN '', ' || COLNAME || ''' ELSE '''' END' AS SELECT_LIST_EXPR
, 'OR A.' || C.COLNAME || ' IS DISTINCT FROM B.' || C.COLNAME AS WHERE_EXPR
FROM
SYSCAT.COLUMNS C
, TABLE
(
SELECT LISTAGG('A.' || U.COLNAME || ' = B.' || U.COLNAME, ' AND ') AS KEY_EXPR
FROM SYSCAT.INDEXES I
JOIN SYSCAT.INDEXCOLUSE U ON U.INDSCHEMA = I.INDSCHEMA AND U.INDNAME = I.INDNAME
WHERE
I.TABSCHEMA=C.TABSCHEMA AND I.TABNAME=C.TABNAME
AND I.INDSCHEMA='SYSIBM' AND I.INDNAME='INDTABLES01'
AND I.UNIQUERULE IN ('P', 'U')
) I
WHERE C.TABSCHEMA='SYSIBM' AND C.TABNAME='SYSTABLES'
--FETCH FIRST 10 ROWS ONLY
;