DB2:如何将多维度表从行转置到列,以发现跨行的数据更改

DB2:如何将多维度表从行转置到列,以发现跨行的数据更改,db2,Db2,我正在使用Db2尝试以下操作: 问题 我有一个表,有80多列和两行 我需要完成的是检查两行之间哪些列更改了值,并返回一个表,其中包含已更改的列名、第1行中的初始值以及第2行中的新值 到目前为止的方法 我最初的想法是将两行转换为两列,第1行作为第1列,第2行作为第2列,然后将一列列名(可能取自syscat.columns)连接到表中作为第3列,在这一点上,我可以选择where column1!=第2列,因此返回包含所有所需数据的行。但遗憾的是,在提出这一点后不久,我发现DB2不支持pivot/un

我正在使用Db2尝试以下操作:

问题

我有一个表,有80多列和两行

我需要完成的是检查两行之间哪些列更改了值,并返回一个表,其中包含已更改的列名、第1行中的初始值以及第2行中的新值

到目前为止的方法

我最初的想法是
将两行转换为两列
,第1行作为第1列,第2行作为第2列,然后将一列列名(可能取自syscat.columns)连接到表中作为第3列,在这一点上,我可以选择where column1!=第2列,因此返回包含所有所需数据的行。但遗憾的是,在提出这一点后不久,
我发现DB2不支持pivot/unpivot…

问题

那么,对于如何在DB2中实现这一点,有什么想法吗

| Col A | Col B | Col C | ... | Col Z|
| ----- | ----- | ----- | --- | ---- |
| Val A | Val B | 123 | ... | 01/01/2021 |
| Val C | Val B | 124 | ... | 02/01/2021 |
并返回列已更改、初始值和新值的表:

| Initial | New | ColName|
| ----- | ----- | ----- |
| Val A | Val C | Col A |
| 123 | 124 | Col C |
| 01/01/2021 | 02/01/2021 | Col Z |
还要注意的是,列数据类型也不同,因此需要转换为varchar

DB2版本是11.1

编辑:也可根据评论请求参考,这是我试图用于实现此目标的代码:

WITH
    INIT AS (SELECT * FROM TABLE WHERE SOMEDATE=(SELECT MIN(SOMEDATE) FROM TABLE),
    LATE AS (SELECT * FROM TABLE WHERE SOMEDATE=(SELECT MAX(SOMEDATE) FROM TABLE),
    COLS AS (SELECT COLNAME FROM SYSCAT.COLUMNS WHERE TABNAME='TABLE' ORDER BY COLNO)
SELECT * FROM (
    SELECT 
        COLNAME AS ATTRIBUTE,
        (SELECT COLNAME AS INITIAL FROM INIT),
        (SELECT COLNAME AS NEW FROM LATE)
    FROM
        COLS
    WHERE
        (INITIAL != NEW) OR (INITIAL IS NULL AND NEW IS NOT NULL) OR (INITIAL IS NOT NULL AND NEW IS NULL));

唯一的问题是,我不知道如何使用COLS表中的值作为要选择的列

如果不想手动键入,您可以轻松生成所需表达式的文本。
如果要在同一个相当宽的表2行中打印不同的列值,请考虑以下示例:代码> SysCAT.TABS/COD>。我们使用以下查询生成这样的表达式

SELECT 
  'DECODE(I.I, ' 
|| LISTAGG(COLNO || ', A.' || COLNAME || CASE WHEN TYPENAME NOT LIKE '%CHAR%' AND TYPENAME NOT LIKE '%GRAPHIC' THEN '::VARCHAR(128)' ELSE '' END, ', ') 
|| ') AS INITIAL' AS EXPR_INITIAL
, 'DECODE(I.I, ' 
|| LISTAGG(COLNO || ', B.' || COLNAME || CASE WHEN TYPENAME NOT LIKE '%CHAR%' AND TYPENAME NOT LIKE '%GRAPHIC' THEN '::VARCHAR(128)' ELSE '' END, ', ')
|| ') AS NEW' AS EXPR_NEW
, 'DECODE(I.I, ' 
|| LISTAGG(COLNO || ', ''' || COLNAME || '''', ', ')
|| ') AS COLNAME' AS EXPR_COLNAME
FROM SYSCAT.COLUMNS C
WHERE TABSCHEMA = 'SYSCAT' AND TABNAME = 'TABLES'
    AND TYPENAME NOT LIKE '%LOB';
表包含多少列并不重要。例如,我们只需过滤掉*LOB类型的列。如果您也需要它们,您应该将
::VARCHAR(128)
强制转换更改为一些
::CLOB(XXX)
。 我们将这3个生成的表达式放在下面查询中的相应位置:

WITH MYTAB AS
(
-- We enumerate the rows to reference them later
SELECT ROWNUMBER() OVER () RN_, T.*
FROM SYSCAT.TABLES T
WHERE TABSCHEMA = 'SYSCAT'
FETCH FIRST 2 ROWS ONLY
)
SELECT *
FROM
(
SELECT
--   Place here the result got in the EXPR_INITIAL column
-- , Place here the result got in the EXPR_NEW column
-- , Place here the result got in the EXPR_COLNAME column
FROM MYTAB A, MYTAB B
, 
(
  SELECT COLNO AS I
  FROM SYSCAT.COLUMNS
  WHERE TABSCHEMA = 'SYSCAT' AND TABNAME = 'TABLES'
    AND TYPENAME NOT LIKE '%LOB'
) I
WHERE A.RN_ = 1 AND B.RN_ = 2
) 
WHERE INITIAL IS DISTINCT FROM NEW;
我在数据库中得到的结果:

|INITIAL                   |NEW                       |COLNAME        |
|--------------------------|--------------------------|---------------|
|2019-06-04-22.44.14.493001|2019-06-04-22.44.14.502001|ALTER_TIME     |
|26                        |15                        |COLCOUNT       |
|2019-06-04-22.44.14.493001|2019-06-04-22.44.14.502001|CREATE_TIME    |
|2019-06-04-22.44.14.493001|2019-06-04-22.44.14.502001|INVALIDATE_TIME|
|2019-06-04-22.44.14.493001|2019-06-04-22.44.14.502001|LAST_REGEN_TIME|
|ATTRIBUTES                |AUDITPOLICIES             |TABNAME        |

Db2的版本和平台是什么?分享您迄今为止尝试过的SQL语句这是否回答了您的问题?该链接中的解决方案确实为DB2中类似于pivot的行为提供了一种方法,但是当涉及到大量列时,它们实际上并不可行,在我的例子中,这将导致80多条Select As语句。