简体   繁体   中英

Oracle SQL - How to merge multiple columns into new one

I need to merge multiple columns (there are quite a lot of columns and rows) into new one column.

Eg. shortened 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

and I'd like to merge Col1-Col5 with comma separator (",") and put created String into Col6

So in Col6 I'd like to have eg: 942,72987,14759,441277503,73553030

Is there any solution how can I do it in SQL / PL/SQL? As I said there are a lot of column so I'd like to avoid to add them manually by using Col1 || Col2 || Col3 || Col4 || Col5Col1 || Col2 || Col3 || Col4 || Col5

Thanks in advance, Michał

You can use trim() with some conditional logic:

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)
           )

I'd follow @APC's route and use a query of USER_TAB_COLUMNS to generate the necessary 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

You can now concatenate them with 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

Now I'd copy and paste this to the appropriate query, fi

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

To concatenate the columns, they need to be converted to VARCHAR2. Oracle tries an automatic datatype conversion. You have to check if this works and is good enough for you. Numbers may have leading spaces, a comma or decimal point, dates may need a format string etc.

You could think of doing it along those lines:

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')

Depending on your circumstances, you may be able to use a virtual column instead of copying the real data:

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

Try PL/SQL block like this:

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;
/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM