Home > front end >  custom columns on demand using select on OracleDB
custom columns on demand using select on OracleDB

Time:10-18

If I have a query returning PARAM_VALUE with multiple values like

PARAM_VALUE
1,2,3,4,5,6

How can I return multiple columns on demand using SELECT to present this data like

PARAM_VALUE1 PARAM_VALUE2 PARAM_VALUE3 ...
1 2 3 ...

CodePudding user response:

SQL (not just Oracle) requires a known, fixed number of output columns. So, if you have a fixed maximum number of delimited values in your string then you can use string functions to find the sub-strings:

SELECT param_value,
       CASE pos1
       WHEN 0
       THEN param_value
       ELSE SUBSTR(param_value, 1, pos1 - 1)
       END AS param_value1,
       CASE 
       WHEN pos1 = 0
       THEN NULL
       WHEN pos2 = 0
       THEN SUBSTR(param_value, pos1   1)
       ELSE SUBSTR(param_value, pos1   1, pos2 - pos1 - 1)
       END AS param_value2,
       CASE 
       WHEN pos2 = 0
       THEN NULL
       WHEN pos3 = 0
       THEN SUBSTR(param_value, pos2   1)
       ELSE SUBSTR(param_value, pos2   1, pos3 - pos2 - 1)
       END AS param_value3,
       CASE 
       WHEN pos3 = 0
       THEN NULL
       WHEN pos4 = 0
       THEN SUBSTR(param_value, pos3   1)
       ELSE SUBSTR(param_value, pos3   1, pos4 - pos3 - 1)
       END AS param_value4
FROM   (
  SELECT param_value,
         INSTR(param_value, ',', 1, 1) AS pos1,
         INSTR(param_value, ',', 1, 2) AS pos2,
         INSTR(param_value, ',', 1, 3) AS pos3,
         INSTR(param_value, ',', 1, 4) AS pos4,
         INSTR(param_value, ',', 1, 5) AS pos5
  FROM   table_name
);

or, more compact, but slower, using regular expressions:

SELECT param_value,
       REGEXP_SUBSTR(param_value, '([^,]*)(,|$)', 1, 1, NULL, 1) AS param_value1,
       REGEXP_SUBSTR(param_value, '([^,]*)(,|$)', 1, 2, NULL, 1) AS param_value2,
       REGEXP_SUBSTR(param_value, '([^,]*)(,|$)', 1, 3, NULL, 1) AS param_value3,
       REGEXP_SUBSTR(param_value, '([^,]*)(,|$)', 1, 4, NULL, 1) AS param_value4
FROM   table_name;

Which, for the sample data:

create table table_name (param_value) AS
  SELECT NULL FROM DUAL UNION ALL
  SELECT 'A' FROM DUAL UNION ALL
  SELECT 'A,B' FROM DUAL UNION ALL
  SELECT 'A,B,C' FROM DUAL UNION ALL
  SELECT 'A,B,C,D' FROM DUAL UNION ALL
  SELECT 'A,B,C,D,E' FROM DUAL;

Both output:

PARAM_VALUE PARAM_VALUE1 PARAM_VALUE2 PARAM_VALUE3 PARAM_VALUE4
null null null null null
A A null null null
A,B A B null null
A,B,C A B C null
A,B,C,D A B C D
A,B,C,D,E A B C D

fiddle

CodePudding user response:

If you want to generate the values for an unknown length of list then generate the values as rows (rather than columns):

SELECT param_value,
       item,
       CASE epos
       WHEN 0
       THEN SUBSTR(param_value, spos)
       ELSE SUBSTR(param_value, spos, epos - spos)
       END AS param
FROM   table_name t
       CROSS APPLY (
         SELECT LEVEL AS item,
                CASE LEVEL
                WHEN 1
                THEN 1
                ELSE INSTR(t.param_value, ',', 1, LEVEL - 1)   1
                END AS spos,
                INSTR(t.param_value, ',', 1, LEVEL) AS epos
         FROM   DUAL
         CONNECT BY INSTR(t.param_value, ',', 1, LEVEL - 1) > 0
       ) b

Which, for the sample data:

create table table_name (param_value) AS
  SELECT NULL FROM DUAL UNION ALL
  SELECT 'A' FROM DUAL UNION ALL
  SELECT 'A,B' FROM DUAL UNION ALL
  SELECT 'A,B,C' FROM DUAL UNION ALL
  SELECT 'A,B,C,D' FROM DUAL UNION ALL
  SELECT 'A,B,C,D,E' FROM DUAL;

Outputs:

PARAM_VALUE ITEM PARAM
null 1 null
A 1 A
A,B 1 A
A,B 2 B
A,B,C 1 A
A,B,C 2 B
A,B,C 3 C
A,B,C,D 1 A
A,B,C,D 2 B
A,B,C,D 3 C
A,B,C,D 4 D
A,B,C,D,E 1 A
A,B,C,D,E 2 B
A,B,C,D,E 3 C
A,B,C,D,E 4 D
A,B,C,D,E 5 E

If you then want it as columns then transpose the data set in whatever third party application you are using to access the database as it is likely to support the output format you want (whereas it would be very difficult to generate a dynamic output using SQL).

fiddle

  • Related