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 || Col5
Col1 || 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.