如何将逗号分隔值放入oracle中的列

时间:2018-04-07 08:20:34

标签: sql json oracle plsql

我有一个JSON响应,在处理完响应后,我的输出如下:

column_variable := 'col1,col2,col3';
data_clob := 
"2017-10-14,abc,1,
2019-10-13,abc,12,
2019-10-12,abc,,
"
;

由于原始回复包含new line的转义字符,data_clob也已相应转换。

如何在oracle表中转换此逗号分隔值:

我的输出应如下所示:

col1            col2     col3 
2017-10-14      abc      1
2019-10-13      abc      12
2019-10-12      abc      null

我正在查看类似的问题,但我不想使用REGEXP_SUBSTR因为我不知道我将在响应中获得的列数。 例如:column_variable可能有'col1,col2,col3,col4,col5,col6';

我正在使用oracle 12.1.0.2.0

请帮忙!

2 个答案:

答案 0 :(得分:1)

使用Polymorphic Table Functions(Oracle 18c)实现它是非常简单的方法:

Dynamic CSV to Columns Converter: Polymorphic Table Function Example

create or replace package csv_pkg as  
  /* The describe function defines the new columns */  
  function describe (  
    tab in out dbms_tf.table_t,  
    col_names varchar2  
  ) return dbms_tf.describe_t;  

  /* Fetch_rows sets the values for the new columns */  
  procedure fetch_rows (col_names varchar2);  
end csv_pkg;  

和身体:

create or replace package body csv_pkg as  
  function describe(  
    tab in out dbms_tf.table_t,  
    col_names varchar2  
  )   
    return dbms_tf.describe_t as  
    new_cols dbms_tf.columns_new_t;  
    col_id   pls_integer := 2;  
  begin   

    /* Enable the source colun for reading */  
    tab.column(1).pass_through := FALSE;  
    tab.column(1).for_read     := TRUE;  
    new_cols(1) := tab.column(1).description;  

    /* Extract the column names from the header string,  
       creating a new column for each   
     */  
    for j in 1 .. ( length(col_names) - length(replace(col_names,',')) ) + 1 loop   
      new_cols(col_id) := dbms_tf.column_metadata_t(  
        name=>regexp_substr(col_names, '[^,]+', 1, j),--'c'||j,   
        type=>dbms_tf.type_varchar2  
      );  
      col_id := col_id + 1;  
    end loop;  

    return dbms_tf.describe_t( new_columns => new_cols );  
  end;  

  procedure fetch_rows (col_names varchar2) as   
    rowset    dbms_tf.row_set_t;  
    row_count pls_integer;  
  begin  
    /* read the input data set */  
    dbms_tf.get_row_set(rowset, row_count => row_count);  

    /* Loop through the input rows... */  
    for i in 1 .. row_count loop  
      /* ...and the defined columns, extracting the relevant value   
         start from 2 to skip the input string  
      */  
      for j in 2 .. ( length(col_names) - length(replace(col_names,',')) ) + 2 loop  
        rowset(j).tab_varchar2(i) :=   
          regexp_substr(rowset(1).tab_varchar2(i), '[^,]+', 1, j - 1);  
      end loop;  
    end loop;  

    /* Output the new columns and their values */  
    dbms_tf.put_row_set(rowset);  

  end;  

end csv_pkg;  

--function
create or replace function csv_to_columns(  
  tab table, col_names varchar2  
) return table pipelined row polymorphic using csv_pkg; 

然后你只需传递:

select *   
from   csv_to_columns( data_clob, column_variable );

答案 1 :(得分:0)

这是一个可能的解决方案,适用于18岁以下,甚至12岁以下的Oracle版本,不确定......这不完美,并会根据您提供的数据在末尾创建一个空列 - 额外的空格,逗号等...这也可能会在“SELECT'”之间创建一个空白区域。和输出中的第一列。所有这些都可以在以后手动删除或使用更多编码。我希望这有助于,至少在某些方面:

SELECT 'SELECT '''||REPLACE(str, chr(10), ''' FROM dual'||chr(10)||'UNION ALL'||chr(10)||'SELECT ''')||''' FROM dual' str
  FROM
  (
   SELECT TRIM(REPLACE(str, ',', ''''||', ''')) str FROM
   (
    SELECT TRIM(BOTH '"' FROM
     '"2017-10-14,abc,1,
       2019-10-13,abc,12,
       2019-10-12,abc,,"') AS str FROM dual
   )
  )
/

这将构建可以手动或使用动态SQL清理和执行的select语句:

SELECT '2017-10-14' col, 'abc' col, '1' col, '' FROM dual
UNION ALL
SELECT '2019-10-13' col, 'abc' col, '12' col, '' FROM dual
UNION ALL
SELECT '2019-10-12' col, 'abc' col, '' col, ''  FROM dual

以上select语句的输出:

COL         COL_1   COL_2
2017-10-14  abc         1
2019-10-13  abc        12
2019-10-12  abc      null