如何在 Oracle (12.1) 存储过程中将 clob 的 json 数组转换为对象类型

How to convert a json array of clob into a object type in Oracle (12.1) stored procedure

我正在尝试将 json 数组转换为 json clob 并将其转换为 Oracle 存储过程中的对象类型。

下面是我在 Oracle 中的对象类型。

create or replace TYPE REPORT_OBJ FORCE as OBJECT (
  id NUMBER,
  name NUMBER,
  createDt Date,
  value NUMBER(10,2)
);

create or replace TYPE REPORT_OBJ_LIST as TABLE OF REPORT_OBJ;

这是我的 json 数组:

[{"id":1,"name":"john",:"createDt":"01-jan-2020","value":10},
{"id":2,"name":"crystal","createDt":"01-feb-2020","value":20},
{"id":3,"name":"bob","createDt":"01-mar-2020","value":30}]

这是我的存储过程,它以 report_obj_list 作为输入参数

create or replace PROCEDURE SaveUpdate_ReportsData(reportList IN REPORT_OBJ_LIST)
AS v_count number;
v_column REPORTS_DATA.id%TYPE;
updatedRecs Number;
recsCount Number;
dbid REPORTS_DATA.Id%TYPE;
dbname REPORTS_DATA.name%TYPE;
dbcreateDt REPORTS_DATA.createDt%TYPE;
dbvalue REPORTS_DATA.value%TYPE;
BEGIN
recsCount := 0;
updatedRecs := 0;
for i in reportList.first..reportList.last loop
v_column := 0;
dbid := 0;
dbname := 0;
dbcreateDt := sysdate;
dbvalue := 0;
BEGIN
    SELECT DISTINCT NVL(b.repId,0) into v_column  from (
    (SELECT 'TEMP' as temp from REPORTS_DATA) a left join (
    SELECT DISTINCT 'TEMP' AS temp, NVL(id,0) as repId FROM REPORTS_DATA
    where createDt = reportList(i).createDt ) b on a.temp = b.temp);
        if(v_column <= 0 ) then 
            INSERT INTO REPORTS_DATA (Id,name,createDt,value)        
            VALUES (reportList(i).Id,reportList(i).name, reportList(i).createDt,
                reportList(i).value);
            updatedRecs := updatedRecs+1;
        else 
            updatedRecs := updatedRecs+1;

            SELECT id,name,createDt,value INTO 
                dbid,dbname,dbcreateDt,dbvalue
                FROM REPORTS_DATA
             where createDt = reportList(i).createDt;

            update REPORTS_DATA set id = NVL(reportList(i).id,dbid), 
                name = NVL(reportList(i).name,dbname) ,
                createDt = NVL(reportList(i).createDt,dbcreateDt),
                value = NVL(reportList(i).value, dbvalue);
     end if;
     EXCEPTION
WHEN NO_DATA_FOUND THEN
v_column := null;
DBMS_OUTPUT.PUT_LINE('hello' || v_column);
    END;
    end loop;
      Commit;
     recsCount:= updatedRecs ;
        DBMS_OUTPUT.PUT_LINE('HELOOwq ' || recsCount);
end SaveUpdate_ReportsData ;
below is the oracle table

create table REPORTS_DATA(
id number,
name varchar(200),
createdt date,
value number(10,2)
);

从 java 开始,我必须将 jsonarray 转换为 clob(以便它可以接受大量数据作为存储过程的输入),并且存储过程应该接受 json clob 数组并将其转换为 'Report_obj_list',现有的存储过程将从那里正常工作。我已经编写了接受对象的存储过程,但我需要进行更改,以便它接受 clob json 数组并将其转换为存储过程中的对象。

更新存储过程

create or replace PROCEDURE SaveUpdate_ReportsData(intnum in Number)
AS v_count number;
jstr clob;
reportList report_obj_list;
v_column REPORTS_DATA.id%TYPE;
dbid REPORTS_DATA.Id%TYPE;
dbname REPORTS_DATA.name%TYPE;
dbcreateDt REPORTS_DATA.createDt%TYPE;
dbvalue REPORTS_DATA.value%TYPE;
BEGIN
jstr := to_clob('[{"id":1,"name":"john","createDt":"01-jan-2020","value":10},
{"id":2,"name":"crystal","createDt":"01-feb-2020","value":20},
{"id":3,"name":"bob","createDt":"01-mar-2020","value":30}]');

select report_obj(id, name, to_date(createdt, 'dd-mon-yyyy'), value) 
  bulk collect into reportList
  from json_table(jstr, '$[*]'
                        columns( id       number        path '$.id',
                                 name    varchar2(20)  path '$.name',
                                 createdt varchar2(11)  path '$.createDt',
                                 value   number(10, 2) path '$.value'
                               )
                 );
for i in reportList.first..reportList.last loop
        DBMS_OUTPUT.PUT_LINE('name_ ' || reportList(i).name);
v_column := 0;
dbid := 0;
dbname := 0;
dbcreateDt := sysdate;
dbvalue := 0;
BEGIN
    SELECT DISTINCT NVL(b.repId,0) into v_column  from (
    (SELECT 'TEMP' as temp from REPORTS_DATA) a left join (
    SELECT DISTINCT 'TEMP' AS temp, NVL(id,0) as repId FROM REPORTS_DATA
    where createDt = reportList(i).createDt ) b on a.temp = b.temp);
        if(v_column <= 0 ) then 
            INSERT INTO REPORTS_DATA (Id,name,createDt,value)        
            VALUES (reportList(i).Id,reportList(i).name, reportList(i).createDt,
                reportList(i).value);
        else 
            SELECT id,name,createDt,value INTO 
                dbid,dbname,dbcreateDt,dbvalue
                FROM REPORTS_DATA
             where createDt = reportList(i).createDt;

            update REPORTS_DATA set id = NVL(reportList(i).id,dbid), 
                name = NVL(reportList(i).name,dbname) ,
                createDt = NVL(reportList(i).createDt,dbcreateDt),
                value = NVL(reportList(i).value, dbvalue);
     end if;
     EXCEPTION
WHEN NO_DATA_FOUND THEN
v_column := null;
    END;
    end loop;
      Commit;
end SaveUpdate_ReportsData ;

我调用存储过程如下:

DECLARE
BEGIN
  SaveUpdate_ReportsData(
   12
  );
END;
/

它没有抛出任何类型的错误,但同时它没有将数据插入 REPORTS_DATA table 甚至没有打印名称。

帮我解决问题

提前致谢。

以下是如何从 JSON(CLOB 数据类型)中提取数据并将其传递给用户定义类型的对象集合(嵌套 table),就像您一样有。 PL/SQL 代码用于接受 CLOB(假设有效 JSON)和 return 对象的嵌套 table 的函数。 (然后我展示了一个调用SQL中的函数的例子,看看里面保存了什么。)

不确定将 JSON 数组转换为 CLOB 是什么意思。就Oracle而言,JSON一个CLOB。

无论如何 - 这是函数:

create or replace type report_obj force as object (
  id       number,
  name_    varchar2(20),
  createdt date,
  value_   number(10,2)
);
/

create or replace type report_obj_list as table of report_obj;
/

create or replace function json_to_obj_list (jstr clob)
  return report_obj_list
as
  lst report_obj_list;
begin
  select report_obj(id, name_, to_date(createdt, 'dd-mon-yyyy'), value_) 
  bulk collect into lst
  from json_table(jstr, '$[*]'
                        columns( id       number        path '$.id',
                                 name_    varchar2(20)  path '$.name',
                                 createdt varchar2(11)  path '$.createDt',
                                 value_   number(10, 2) path '$.value'
                               )
                 );
  return lst;
end;
/

(如您所见,我更改了您的对象类型定义 - 我将属性名称 namevalue 更改为 name_value_,因为 namevalue 是 Oracle 关键字,因此不应将它们用作标识符。)

这是它的工作原理。请注意,我将显式 CLOB 传递给函数。更有可能的是,您希望将 CLOB 存储在某处(table?)并从那里传递它们。那部分比较琐碎。

select * from json_to_obj_list(
to_clob(
'[{"id":1,"name":"john","createDt":"01-jan-2020","value":10},
{"id":2,"name":"crystal","createDt":"01-feb-2020","value":20},
{"id":3,"name":"bob","createDt":"01-mar-2020","value":30}]')
);

        ID NAME_                CREATEDT        VALUE_
---------- -------------------- ----------- ----------
         1 john                 01-jan-2020         10
         2 crystal              01-feb-2020         20
         3 bob                  01-mar-2020         30

注意createdt实际上是date数据类型;在输出中它看起来像你的输入只是因为我故意设置我的 nls_date_format 来匹配它。否则,您的查询将 return 该列中的日期采用会话的默认格式。