将动态 JSON 解析为 Oracle 表

Posted

技术标签:

【中文标题】将动态 JSON 解析为 Oracle 表【英文标题】:Parsing dynamic JSON into Oracle table 【发布时间】:2019-12-05 15:55:10 【问题描述】:

我有一个带有这样一个表的 Oracle 12c 数据库

    (
      MSISDN        VARCHAR2(15 BYTE),
      DOCUMENT      VARCHAR2(15 BYTE),
      LOAD_DATE     DATE,
      LIST_NAME     VARCHAR2(40 BYTE),
      ATRIB         VARCHAR2(40 BYTE),
      VALUE         VARCHAR2(200 BYTE)
    )

另一方面,我有这个 JSON,其中包含该表的数据


   "DigitalClient":
      "documentNumber":"99999999-R",
      "documentType":"PASSPORT",
      "lastLineDate":123213213213,
      "lastClientDate":123213213213,
      "segment":"EMPRESA"
   ,
   "ADSL":
      "idOrder":216668542,
      "status":"COMPLETED",
      "orderType":"STANDARD",
      "documentNumber":"161893223R",
      "technologyAccess":"FTTVULA",
      "dUserLastModifiedDate":1571329345000,
      "type":"PERSON"
   

想法是这样解析表格中的这些信息:

MSISDN       DOCUMENT       LOAD_DATE       LIST_NAME      ATRIB           VALUE
------       ---------      -----------     ------------   --------        -----
911231231    6745671A       05/12/19        DigitalClient  documentNumber  99999999R
911231231    6745671A       05/12/19        DigitalClient  documentType    PASSPORT
911231231    6745671A       05/12/19        ADSL           idOrder         216668542
...

前三个字段是在JSON文件之外获取的,JSON文件相关字段是后三个。可以看到,字段 LIST_NAME 填充的是一级名称,而 ATRIB 和 VALUE 字段填充的是二级名称和值

现在,最困难的部分。 JSON 结构每天都在变化。我不知道 JSON 文件包含什么,既不知道一级或二级字段名称,也不知道有多少结构。我唯一知道的是该文件只有两层深:第一层是属性列表的名称,第二层是每个列表的属性及其值。

有人知道实现这一目标的好方法吗?我尝试了showed here 的解决方案,但不是我想要的,因为我必须在第一列中使用 SUBSTR 提取 LIST_NAME 和 ATRIB 信息,并且对于加载大量记录不是很有效。

提前致谢!

【问题讨论】:

检查这里,这可能会有所帮助:blogs.oracle.com/apex/tips-for-parsing-json-in-apex 感谢您的建议,但首先我将尝试使用 Oracle 12c 的原生 JSON 包 【参考方案1】:

如果您使用的是 12.2,则可以使用 JSON Data Guide 为您创建视图:

create table t (
  jdata varchar2(1000)
    check ( jdata is json )
);

create search index ji 
  on t ( jdata )
  for json
  parameters ( 'sync (on commit)' );

insert into t values ('
   "DigitalClient":
      "documentNumber":"99999999-R",
      "documentType":"PASSPORT",
      "lastLineDate":123213213213,
      "lastClientDate":123213213213,
      "segment":"EMPRESA"
   ,
   "ADSL":
      "idOrder":216668542,
      "status":"COMPLETED",
      "orderType":"STANDARD",
      "documentNumber":"161893223R",
      "technologyAccess":"FTTVULA",
      "dUserLastModifiedDate":1571329345000,
      "type":"PERSON"
   
');

commit;

begin
  dbms_json.create_view_on_path ( 
    'vw', 't', 'jdata', '$'
  ); 
end;
/

select * from vw;

JDATA$type   JDATA$status   JDATA$idOrder   JDATA$orderType   JDATA$documentNumber   JDATA$technologyAccess   JDATA$dUserLastModifiedDate   JDATA$segment   JDATA$documentType   JDATA$lastLineDate   JDATA$documentNumber_1   JDATA$lastClientDate   
PERSON        COMPLETED              216668542 STANDARD           161893223R              FTTVULA                                    1571329345000 EMPRESA          PASSPORT                       123213213213 99999999-R                           123213213213 

请注意,您需要 is json 约束和搜索索引才能使其工作。

如果 JSON 包含一个数组,您将在输出中为每个元素获得一行。

例如:

insert into t values ( ' "aDifferent" : ["array", "of", "stuff"] ' );
commit;

begin
  dbms_json.create_view_on_path ( 
    'vw', 't', 'jdata', '$'
  ); 
end;
/

select * from vw;

JDATA$type JDATA$status  JDATA$idOrder JDATA$orderType JDATA$documentNumber JDATA$technologyAccess  JDATA$dUserLastModifiedDate JDATA$segment JDATA$documentType JDATA$lastLineDate JDATA$documentNumber_1 JDATA$lastClientDate JDATA$string   
PERSON     COMPLETED         216668542 STANDARD        161893223R           FTTVULA                               1571329345000 EMPRESA       PASSPORT                 123213213213 99999999-R                     123213213213 <null>          
<null>     <null>               <null> <null>          <null>               <null>                                       <null> <null>        <null>                         <null> <null>                               <null> array           
<null>     <null>               <null> <null>          <null>               <null>                                       <null> <null>        <null>                         <null> <null>                               <null> of              
<null>     <null>               <null> <null>          <null>               <null>                                       <null> <null>        <null>                         <null> <null>                               <null> stuff           

如果 JSON 文档中的属性名称发生变化,那么您将不断在视图中获取新列。因此,您可能希望在创建它之前删除它。

【讨论】:

嗨,克里斯,感谢您的回答。我正在尝试您的解决方案,当我尝试创建视图时,我遇到了这个错误(我的数据库是西班牙语,对此感到抱歉) ORA-06502: PL/SQL: error : error de conversión de carácter a número numérico o de valor ORA-06512: en "SYS.DBMS_JSON0", línea 24 ORA-06512: en "XDB.DBMS_JSON", línea 1000 ORA-06512: en línea 1 另外,我有一个疑问,你建议我如何获得“列表名称”信息?虚拟列名称不引用它:JDATA$documentNumber 可以属于 DigitalClient 或 ADSL 列表,我怎么知道这 2 个列表中的哪一个是正确的?谢了! 不知道为什么你会得到这个错误 - 请发布一个新问题,说明你是如何到达这个的(创建表 + 插入 + dbms_json 调用) 如果您知道要获取哪个对象的属性,您可以在该路径上创建一个视图,例如dbms_json.create_view_on_path ( 'vw', 't', 'jdata', '$.ADSL' ); 。您也可以使用select json_dataguide ( jdata ) from t; 检查结构 我在本地测试数据库中逐步按照您的示例进行操作时遇到此错误。可能是配置问题? 关于您的第二条评论,问题是我不知道对象名称,因为 JSON 不是固定的,它具有可变数量的信息和对象属性结构。这就是我发疯的原因:-)

以上是关于将动态 JSON 解析为 Oracle 表的主要内容,如果未能解决你的问题,请参考以下文章

解析 JSON 并绑定到动态创建的 HTML 表的行和列

使用JSON动态添加表行

C# 将动态 JSON JToken 解析为列表

oracle 动态传入表名,怎么做? 高手指点

ORACLE动态采样

php创建动态html表