Oracle SQL - 如何将多列合并为新列

Posted

技术标签:

【中文标题】Oracle SQL - 如何将多列合并为新列【英文标题】:Oracle SQL - How to merge multiple columns into new one 【发布时间】:2020-05-28 13:34:05 【问题描述】:

我需要将多列(有很多列和行)合并到新的一列中。

例如。缩短的 test_table

Col1    Col2    Col3    Col4    Col5    Col6
942 72987   14759   441277503   73553030    null
943 72987   14759   441278315   73553166    null
944 72987   14759   441362593   73570082    null
945 72987   14759   441380217   73572619    null
946 72987   14759   441394189   73574533    null
947 72987   14759   441394189   73574533    null

我想将 Col1-Col5 与逗号分隔符 (",") 合并,并将创建的 String 放入 Col6

所以在 Col6 中,我想拥有例如: 942,72987,14759,441277503,73553030

有什么解决方案可以在 SQL/PL/SQL 中执行吗? 正如我所说的有很多列,所以我想避免使用Col1 || Col2 || Col3 || Col4 || Col5手动添加它们

提前致谢, 米哈乌

【问题讨论】:

不。手动是您唯一的选择。虽然如果您想对很多表执行此操作,您可以从数据字典中生成代码。 列为 NULL 时会发生什么?您的列的数据类型是什么? @wolφi - 如果列为 Null,那么它应该只是空白值。并且数据类型不同,主要是 VARCHAR2,但其中一些是 NUMBERs 编辑了我的答案以处理数据类型和转换。请看meta.stackexchange.com/questions/5234/… 【参考方案1】:

您可以将trim() 与一些条件逻辑一起使用:

select trim(leading ',' from
            (case when col1 is not null then ',' || col1 else '' end) ||
            (case when col2 is not null then ',' || col2 else '' end) ||
            (case when col3 is not null then ',' || col3 else '' end) ||
            (case when col4 is not null then ',' || col4 else '' end) ||
            (case when col5 is not null then ',' || col5 else '' end)
           )

【讨论】:

【参考方案2】:

尝试这样的 PL/SQL 块:

SET SERVEROUT ON
DECLARE
    LV_COLUMNS VARCHAR2(20000);
BEGIN
    SELECT LISTAGG('CASE WHEN ' || COLUMN_NAME || ' IS NOT NULL THEN ' || COLUMN_NAME || ' || '',''|| '
      || 'ELSE NULL END'
      , '||') WITHIN GROUP(ORDER BY COLUMN_ID)
      INTO LV_COLUMNS
      FROM USER_TAB_COLS
     WHERE TABLE_NAME = 'YOUR_TABLE_NAME'
       AND COLUMN_NAME <> 'COL6'
       AND HIDDEN_COLUMN = 'NO';

    DBMS_OUTPUT.PUT_LINE('UPDATE YOUR_TABLE_NAME SET COL6 = TRIM('','' FROM (' || LV_COLUMNS || '))');
    EXECUTE IMMEDIATE 'UPDATE YOUR_TABLE_NAME SET COL6 = TRIM('','' FROM (' || LV_COLUMNS || '))';
    COMMIT;
END;
/

【讨论】:

【参考方案3】:

我会遵循@APC 的路线并使用USER_TAB_COLUMNS 的查询来生成必要的SQL:

CREATE TABLE t (col1 VARCHAR2(5), col2 NUMBER, col3 VARCHAR2(30), 
                col4 VARCHAR2(7), col5 DATE,   col6 VARCHAR2(200));
SELECT column_name
  FROM user_tab_columns
 WHERE table_name = 'T'
   AND column_name <> 'COL6';

COL1
COL2
COL3
COL4
COL5

您现在可以将它们与LISTAGG 连接起来:

SELECT LISTAGG(column_name, '||'',''||') 
       WITHIN GROUP (ORDER BY column_id) AS sql
  FROM user_tab_columns
 WHERE table_name = 'T'
   AND column_name <> 'COL6';

COL1||','||COL2||','||COL3||','||COL4||','||COL5

现在我将其复制并粘贴到相应的查询中,f.i.

UPDATE t 
   SET col6 = COL1||','||COL2||','||COL3||','||COL4||','||COL5;

要连接列,需要将它们转换为 VARCHAR2。 Oracle 尝试进行自动数据类型转换。您必须检查这是否有效并且对您来说足够好。数字可能有前导空格、逗号或小数点,日期可能需要格式字符串等。

你可以考虑按照这些思路来做:

SELECT column_name, 
       CASE WHEN data_type IN ('NUMBER','FLOAT') 
              THEN 'TO_CHAR('||column_name||')'
            WHEN data_type IN ('DATE') 
              THEN 'TO_CHAR('||column_name||',''YYYY-MM-DD'')'
            ELSE column_name
        END AS cstr
  FROM user_tab_columns
 WHERE table_name = 'T'
   AND column_name <> 'COL6';

COL1   COL1
COL2   TO_CHAR(COL2)
COL3   COL3
COL4   COL4
COL5   TO_CHAR(COL5,'YYYY-MM-DD')

根据您的情况,您可以使用虚拟列而不是复制真实数据:

ALTER TABLE t DROP COLUMN col6; 
ALTER TABLE t ADD (col6 NUMBER GENERATED ALWAYS 
               AS (COL1||','||COL2||','||COL3||','||COL4||','||COL5));

【讨论】:

以上是关于Oracle SQL - 如何将多列合并为新列的主要内容,如果未能解决你的问题,请参考以下文章

将向量合并为 df,并将向量名称转换为新列的行

将多列合并为一个新列,同时保留原始列

如何合并同一数据框的多列

如何使用 Python Pandas 合并多个 CSV 文件

如何将 pandas 列中的 JSON 数据转换为新列

SQL 动态地将值拆分为新列