简体   繁体   English

Oracle SQL:将PL/SQL中的JSON解析为表或数组

[英]Oracle SQL: Parse JSON in PL/SQL to table or array

I need to parse JSON to a table or array.我需要将 JSON 解析为表或数组。 As this is completely new for me I've used Google for help but something is not working for me:/因为这对我来说是全新的,所以我使用谷歌寻求帮助,但有些东西对我不起作用:/

My JSON looks like:我的 JSON 看起来像:

{
  "statusCode": 200,
  "isValid": true,
  "errors": [],
  "result": {
    "optimizationData": [
      {
        "name": "out",
        "content": "ID_LIMIT;TIME_STAMP_FROM;DIRECTION;ID_MODEL_CONSTRAINT\n1;202109222200;G;2_7_1_G\n1;202109232200;G;2_3_1_G\n2;202109222200;G;2_3_1_G\n3;202109222200;G;3_3_1_P\n"
      },
      {
        "name": "unit_out",
        "content": "ID_LIMIT;CODE_UNIT;TIME_STAMP_FROM;TIME_STAMP_TO;VARIABLE;VALUE\n1;BEL 2-02;202109222200;202109232200;RelaxationPlus;10\n1;BEL 2-05;202109222200;202109232200;RelaxationPlus;10\n2;WLO 1-01;202109222200;202109232200;RelaxationMinus;10\n"
      }
    ]
  }
}

From above JSON I'd like to create table (or arrays) like below (example expected data for name: "unit_out"):从上面 JSON 我想创建如下表(或数组)(名称的预期数据示例:“unit_out”):

ID_LIMIT ID_LIMIT CODE_UNIT CODE_UNIT TIME_STAMP_FROM TIME_STAMP_FROM TIME_STAMP_TO TIME_STAMP_TO VARIABLE多变的 VALUE价值
1 1个 BEL 2-02贝尔 2-02 202109222200 202109222200 202109232200 202109232200 RelaxationPlus放松加 10 10
1 1个 BEL 2-05贝尔 2-05 202109222200 202109222200 202109232200 202109232200 RelaxationPlus放松加 10 10
2 2个 WLO 1-01世界冠军联赛 1-01 202109222200 202109222200 202109232200 202109232200 RelaxationMinus放松减号 10 10

So far I've tried to wrote a function to return "content" value, but I'm getting ORA-30625 (method dispatch on null self argument is disallowed)到目前为止,我已经尝试编写一个 function 来返回“内容”值,但我得到的是 ORA-30625(null self 参数上的方法调度是不允许的)

CREATE OR REPLACE FUNCTION parse_json (json IN VARCHAR2)
  RETURN VARCHAR2 IS
  json_obj_in  JSON_OBJECT_T;
  json_arr     JSON_ARRAY_T;
  json_elem    JSON_ELEMENT_T;
  json_obj     JSON_OBJECT_T;
  name         varchar2(32000);
  content      varchar2(32000);

BEGIN
  json_obj_in := JSON_OBJECT_T.parse(json);

  json_arr := json_obj_in.get_Array('result');

  FOR i IN 0 .. json_arr.get_size - 1 --NVL(json_arr.FIRST, 1) .. NVL(json_arr.LAST, 0)
  LOOP
    json_obj := JSON_OBJECT_T(json_arr.get(i));

    name := json_obj.get_Object('optimizationData').get_string('name');
    content := json_obj.get_Object('optimizationData').get_string('content');

  END LOOP;

  RETURN json_obj_in.to_string;
END;

I'm not sure what's wrong or if my approach to this task is correct.我不确定哪里出了问题,或者我对这项任务的处理方法是否正确。

Can anyone help?谁能帮忙?

Thanks谢谢

From Oracle 12, you can do all the parsing in an SQL query.从 Oracle 12,你可以在 SQL 查询中进行所有解析。 Your main issue is not the JSON but that you have your data in strings and you will need to split those into lines and then into value and correlate the values with the headers:你的主要问题不是 JSON 但你的数据是字符串,你需要将它们分成几行然后分成值并将值与标题相关联:

SELECT p.*
FROM   (
  SELECT l.lineno,
         kv.key,
         kv.value
  FROM   table_name t
         CROSS APPLY JSON_TABLE(
           t.value,
           '$.result.optimizationData[*]?(@.name == "unit_out")'
           COLUMNS
             content CLOB PATH '$.content'
         ) j
         CROSS JOIN LATERAL (
           SELECT LEVEL AS lineno,
                  REGEXP_SUBSTR(j.content, '.+', 1, 1 ) AS header,
                  REGEXP_SUBSTR(j.content, '.+', 1, LEVEL ) AS line
           FROM   DUAL
           WHERE  LEVEL > 1
           CONNECT BY LEVEL <= REGEXP_COUNT(j.content, '.+')
         ) l
         CROSS JOIN LATERAL (
           SELECT CAST(REGEXP_SUBSTR(header, '[^;]+', 1, LEVEL) AS VARCHAR2(4000))
                    AS key,
                  CAST(REGEXP_SUBSTR(line, '[^;]+', 1, LEVEL) AS VARCHAR2(4000))
                    AS value
           FROM   DUAL
           CONNECT BY LEVEL <= REGEXP_COUNT(header, '[^;]+')
         ) kv
) pt
PIVOT (
  MAX(value)
  FOR key IN (
    'ID_LIMIT'        AS id_limit,
    'CODE_UNIT'       AS code_limit,
    'TIME_STAMP_FROM' AS time_stamp_from,
    'TIME_STAMP_TO'   AS time_stamp_to,
    'VARIABLE'        AS variable,
    'VALUE'           AS value
  )
) p

Which, for the sample data:其中,对于示例数据:

CREATE TABLE table_name (value BLOB CHECK (value IS JSON));

INSERT INTO table_name (value) VALUES (
'{
  "statusCode": 200,
  "isValid": true,
  "errors": [],
  "result": {
    "optimizationData": [
      {
        "name": "out",
        "content": "ID_LIMIT;TIME_STAMP_FROM;DIRECTION;ID_MODEL_CONSTRAINT\n1;202109222200;G;2_7_1_G\n1;202109232200;G;2_3_1_G\n2;202109222200;G;2_3_1_G\n3;202109222200;G;3_3_1_P\n"
      },
      {
        "name": "unit_out",
        "content": "ID_LIMIT;CODE_UNIT;TIME_STAMP_FROM;TIME_STAMP_TO;VARIABLE;VALUE\n1;BEL 2-02;202109222200;202109232200;RelaxationPlus;10\n1;BEL 2-05;202109222200;202109232200;RelaxationPlus;10\n2;WLO 1-01;202109222200;202109232200;RelaxationMinus;10\n"
      }
    ]
  }
}'
);

Outputs:输出:

LINENO线诺 ID_LIMIT ID_LIMIT CODE_LIMIT代码_LIMIT TIME_STAMP_FROM TIME_STAMP_FROM TIME_STAMP_TO TIME_STAMP_TO VARIABLE多变的 VALUE价值
2 2个 1 1个 BEL 2-02贝尔 2-02 202109222200 202109222200 202109232200 202109232200 RelaxationPlus放松加 10 10
3 3个 1 1个 BEL 2-05贝尔 2-05 202109222200 202109222200 202109232200 202109232200 RelaxationPlus放松加 10 10
4 4个 2 2个 WLO 1-01世界冠军联赛 1-01 202109222200 202109222200 202109232200 202109232200 RelaxationMinus放松减号 10 10

db<>fiddle here db<> 在这里摆弄

I'm leaving you with an example that worked for me in Oracle 12c :我留给你一个在Oracle 12c中对我有用的例子:

INSERT INTO table(param_id, name, label, parameterIndex, notNull, parameterTypeName, default_value, lov_query)
      SELECT param_id, name, label, parameterIndex, notNull, parameterTypeName, default_value, lov_query FROM JSON_TABLE(l_json,
      '$.parameters[*]' COLUMNS (
        param_id PATH '$.id', name PATH '$.name', 
        label PATH '$.label', 
        parameterIndex PATH '$.parameterIndex', 
        notNull PATH '$.notNull', 
        parameterTypeName PATH '$.parameterType.parameterTypeName', 
        default_value PATH '$.parameterAttributes.attributeSelectedOption.attributeValue',
        lov_query PATH '$.parameterQuery'
        ) );

I don't know if it's considered a good practice and somebody do correct me if I'm wrong.我不知道这是否被认为是一种好的做法,如果我错了,有人会纠正我。 This worked for me.这对我有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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