JSON提取子键+值数组

Posted

技术标签:

【中文标题】JSON提取子键+值数组【英文标题】:JSON extract sub key+value array 【发布时间】:2021-02-03 21:05:37 【问题描述】:

在 Oracle Pl/sql 中,type="complaint" 的以下 json 格式如何获取“partialSuccessWarning”元素全文数据值以进行进一步处理?

我是 json pl/sql 的新手,感谢任何帮助

JSON 数据:

[
  
    "type": "customer",
    "existingCount": 2,
    "createdCount": 0,
    "partialSuccessCount": 0,
    "erroredCount": 0,
    "totalCount": 8,
    "createdRecords": [
      
    ],
    "existingRecords": [
      "791304",
      "2154046"
    ],
    "error": 
      
    ,
    "partialSuccessWarning": 
      
    
  ,
  
    "type": "complaint",
    "existingCount": 3,
    "createdCount": 2,
    "partialSuccessCount": 3,
    "erroredCount": 0,
    "totalCount": 8,
    "createdRecords": [
      "VS-548982"
    ],
    "existingRecords": [
      "VS-548988",
      "VS-548986",
      "VS-548984"
    ],
    "error": 
      
    ,
    "partialSuccessWarning": 
      "VS-548986": [
        "[TLM-TEST-SERIAL] does not exist or could not be loaded."
      ],
      "VS-548984": [
        "[TLM-TEST-SERIAL] does not exist or could not be loaded."
      ],
      "VS-548982": [
        "[TLM-TEST-SERIAL] does not exist or could not be loaded."
      ]
    
  
]

【问题讨论】:

【参考方案1】:

您可以直接使用带有JSON_TABLE()函数的SQL,该函数从Oracle DB 12.1.0.2版本开始可用,但是您需要获取值并进一步使用,然后通过创建存储函数将返回值分配给一些变量返回类型为SYS_REFCURSOR

CREATE OR REPLACE FUNCTION Get_Warnings RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  JsonArray   VARCHAR2(32767);
  arrWarnings VARCHAR2(1000);
  v_sql       VARCHAR2(32767);
BEGIN
  JsonArray :='[
                
                  "type": "customer",
                  "existingCount": 2,
                   ...
                
              ]';
  arrWarnings := JSON_QUERY(JsonArray, '$');
  DBMS_OUTPUT.PUT_LINE(arrWarnings);

  v_sql :=
      'SELECT "VS-548986","VS-548984","VS-548982"
         FROM dual
        CROSS JOIN JSON_TABLE(:Warnings,
                                     ''$'' COLUMNS(NESTED PATH ''$[*]."partialSuccessWarning"''
                                                  COLUMNS(
                                                          "VS-548986"  VARCHAR2(1000) PATH ''$."VS-548986"[*]'',
                                                          "VS-548984"  VARCHAR2(1000) PATH ''$."VS-548982"[*]'',
                                                          "VS-548982"  VARCHAR2(1000) PATH ''$."VS-548982"[*]''
                                                          )
                                                )
                        )';
  OPEN v_recordset FOR v_sql USING arrWarnings;
  RETURN v_recordset;
END;
/

然后从 SQL Developer 的控制台调用

SQL> DECLARE
      result SYS_REFCURSOR;
BEGIN
   :result := Get_Warnings;
END;
/

SQL> PRINT result ;

Demo

编辑:Oracle12c内的JSONJSON_TABLEJSON_VALUEJSON_QUERY的函数数量有限,而我们需要确定JSON 表达式的键。然后我们可以选择使用正则表达式函数来提取键值,以便动态构造 SQL 语句(v_sql)和JSON_TABLE(),以创建以下函数的方式,考虑到原始JSON 的简化形式格式如下

CREATE OR REPLACE FUNCTION Get_Warnings RETURN SYS_REFCURSOR IS
      v_recordset SYS_REFCURSOR;
      JsonArray   VARCHAR2(32767);
      arrWarnings VARCHAR2(1000);
      v_sql       VARCHAR2(32767);
      v_keys      VARCHAR2(32767);
      v_cols      VARCHAR2(32767);
BEGIN
      JsonArray :='[
                    
                      "partialSuccessWarning": 
                        "VS-548986": [
                          "aaa"
                        ],
                        "VS-548984": [
                          "bbb"
                        ],
                        "VS-548982": [
                          "ccc"
                        ]
                      
                    
                  ]';
      arrWarnings := JSON_QUERY(JsonArray, '$');

        WITH t(JA) AS
        (
         SELECT JSON_QUERY(JsonArray, '$[*]."partialSuccessWarning"')
           FROM dual
        ), t2 AS
        (                
           SELECT REGEXP_REPLACE( REGEXP_SUBSTR( JA , '[^[]+',1,level ), '(.*")(\S+)(":.*)', '\2') AS keys, level AS lvl
             FROM t
          CONNECT BY level <= REGEXP_COUNT( JA, '\["' )
        )
        SELECT LISTAGG( '"'||keys||'"',',') WITHIN GROUP (ORDER BY lvl),
               LISTAGG( '"'||keys||'" VARCHAR2(1000) PATH ''$."'||keys||'"[*]''',',') WITHIN GROUP (ORDER BY lvl)
          INTO v_keys, v_cols     
          FROM t2; 

      v_sql :=
      'SELECT '||v_keys||
      '  FROM dual
        CROSS JOIN JSON_TABLE(:Warnings,
                              ''$'' COLUMNS(NESTED PATH ''$[*]."partialSuccessWarning"''
                                            COLUMNS('||v_cols||')
                                            )
                   )';
      OPEN v_recordset FOR v_sql USING arrWarnings;
      RETURN v_recordset;
END;
/

这会产生结果

VS-548986 VS-548984 VS-548982
aaa bbb ccc

【讨论】:

感谢您的回复..让我用简单的例子说清楚。下面是 myJSON 的示例 1)在我的情况下,列名“open”、“close”是动态的,但总会有两个……所以不确定如何通过不知道列的位置表示法读取 2)作为一种解决方法,我想我会循环遍历“数据”键、值……但是如何获取“数据”全文? VS-548986,VS-548984 在我的情况下是动态的。实际上,目标是在“partialSuccessWarning”下打印那些任何帮助表示赞赏 好吧,我已经添加了动态案例@RaviKiran

以上是关于JSON提取子键+值数组的主要内容,如果未能解决你的问题,请参考以下文章

Bigquery:是不是有一种 json 路径方法可以仅从具有动态键的 json 数组中提取值?

从 Presto 中的 JSON 数组中提取值

从 BigQuery 中的 JSON 数组中提取多个值

Jmeter之JSON提取器获取数组类型的数据

从 BigQuery 数据 JSON 中的数组中提取索引值

使用 TSQL OPENJSON 如何从具有动态键名的 JSON 数组中提取值