使用Oracle PL / SQL将字符串转换为JSON对象

时间:2019-07-05 03:08:25

标签: json oracle plsql

我在oracle数据目录中有一个“ input.json”文件。我可以使用UTL_FILE命令以PL / SQL代码读取文件。现在这些都是字符串格式,我想将其转换为JSON字符串,并使用PL / SQL块将其全部解析。 我正在使用oracle 12.2。

这是我的JSON输入文件内容:

{
    "CAR":["%HON%","%UZU%"],
    "NAME":["%RAY%","%OE%"];
}
Create or Replace procedure TEST1 as
    fHandle   UTL_FILE.FILE_TYPE;
    s varchar(200);
    -- begin Reading of code
BEGIN
     fHandle := UTL_FILE.FOPEN('DISCOVERY', 'input.json', 'r');
     Loop
         UTL_FILE.get_line(fHandle,s);
         dbms_output.put_line(s);
     end loop; 
     UTL_FILE.fclose(fHandle);
END;

预期输出是有效的JSON字符串

CAR:"%HON%"
CAR:"%UZU%"
NAME:"%RAY%"
NAME:"%OE%"

3 个答案:

答案 0 :(得分:2)

您可以:

  • 创建一个外部表以读取文件
  • 使用JSON_table将文档转换为关系行和列

看上去像:

/* Create the file */
create or replace directory tmp as '/tmp';
declare
  f utl_file.file_type;
begin
  f := utl_file.fopen ('TMP', 'input.json', 'w');
  utl_file.put_line ( f, '{ "CAR":["%HON%","%UZU%"], "NAME":["%RAY%","%OE%"] }');
  utl_file.fclose(f);
end;
/

create table json_ext (
  json_doc varchar2(100)
) organization external (
  default directory tmp
  access parameters (
    records delimited by newline
    fields (
      json_doc char(1000)
    )
  )
  location ( 'input.json' )
);

select * from json_ext;

JSON_DOC                                               
{ "CAR":["%HON%","%UZU%"], "NAME":["%RAY%","%OE%"] } 

select * 
from   json_ext, 
       json_table (
         json_doc, '$'
         columns (
           nested path '$.CAR[*]' columns (
             CAR path '$'
           ),
           nested path '$.NAME[*]' columns (
             NAME path '$'
           )
         )
       );

JSON_DOC                                                CAR       NAME     
{ "CAR":["%HON%","%UZU%"], "NAME":["%RAY%","%OE%"] }    %HON%     <null>    
{ "CAR":["%HON%","%UZU%"], "NAME":["%RAY%","%OE%"] }    %UZU%     <null>    
{ "CAR":["%HON%","%UZU%"], "NAME":["%RAY%","%OE%"] }    <null>    %RAY%     
{ "CAR":["%HON%","%UZU%"], "NAME":["%RAY%","%OE%"] }    <null>    %OE%   

这会将每个数组拆分为自己的一组行和列。要将其作为属性名称和数组值的单个列表,可以unpivot结果:

with rws as (
  select j.* 
  from   json_ext, 
         json_table (
           json_doc, '$'
           columns (
             nested path '$.CAR[*]' columns (
               CAR path '$'
             ),
             nested path '$.NAME[*]' columns (
               NAME path '$'
             )
           )
         ) j
) 
  select * from rws 
  unpivot ( 
    val for attr in ( CAR, NAME )
  );

ATTR    VAL     
CAR     %HON%    
CAR     %UZU%    
NAME    %RAY%    
NAME    %OE%  

答案 1 :(得分:0)

这需要循环遍历JSON元素,然后遍历其数组元素。从this Post

借来的想法
SET SERVEROUTPUT ON
DECLARE
     l_json CLOB := '{
    "CAR" :["%HON%","%UZU%"],
    "NAME":["%RAY%","%OE%" ]
}';
     l_json_obj json_object_t;
     l_keys json_key_list;
     l_arr json_array_t;
     elem json_element_t;
BEGIN
     l_json_obj := json_object_t(l_json);
     l_keys := l_json_obj.get_keys;
     FOR i IN 1..l_keys.count LOOP
          l_arr :=  l_json_obj.get_array(l_keys(i));
          FOR j IN 0..l_arr.get_size - 1 LOOP
               elem := l_arr.get(j);
               dbms_output.put(l_keys(i)
                               || ':');
               dbms_output.put_line(elem.stringify);
          END LOOP;

     END LOOP;

END;
/

结果

CAR:"%HON%"
CAR:"%UZU%"
NAME:"%RAY%"
NAME:"%OE%"

答案 2 :(得分:0)

您可以使用正则表达式执行此操作:

Create or Replace procedure TEST1 as
  fHandle   UTL_FILE.FILE_TYPE;
  s varchar(200);
BEGIN
  fHandle := UTL_FILE.FOPEN('DISCOVERY', 'input.json', 'r');

  WHILE TRUE LOOP
    BEGIN
      UTL_FILE.get_line(fHandle, s);

      IF s <> '{' AND s <> '}' THEN
        FOR aRow IN (SELECT REGEXP_SUBSTR(s, '[^:]*', 1, 1) AS COL1,
                            REGEXP_SUBSTR(s, '"%[^,]*%"', 1, 1) AS COL2,
                            REGEXP_SUBSTR(s, '"%[^,]*%"', 1, 2) AS COL3
                       FROM DUAL)
        LOOP
          DBMS_OUTPUT.PUT_LINE(COL1 || ':' || COL2);
          DBMS_OUTPUT.PUT_LINE(COL1 || ':' || COL3);
        END LOOP;
      END IF;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        EXIT;
    END;
  end loop; 

  UTL_FILE.fclose(fHandle);
END TEST1;