Bo's Oracle Station

【博客文章2025】使用JSON_TABLE和NESTED PATH运算符构造所需结果集

2025-1-15 14:07| 发布者: admin| 查看: 49| 评论: 0|原作者: Bo Tang

摘要: JSON数据通常有多个层次的数据包裹关系。为了利用这些数据来构造“明细清单”表结构,需要使用JSON_TABLE配合NESTED PATH运算符(甚至嵌套的NESTED PATH)逐层向下级层次钻探,以便在内存中映射JSON数据为表结构。本博客给出详细的例子和讲解。特别指出在JSON_TABLE的不同写法中,虽然“点层次表示法”是JSON_TABLE允许的语法,但是如果有多个同级别的数据嵌套并存时, 必须使用NESTED PATH展平多层嵌套数据。
【博客文章2025】使用JSON_TABLE和NESTED PATH运算符构造所需结果集


Author: Bo Tang

1. JSON数据可以有多个层次的数据包裹关系:

    如下JSON数据,按照以下顺序:红色-黄色-绿色-灰色,来依次展示4层包裹关系(实验环境来自https://www.botangdb.com/mytec/mytec_basicadmin/202412/00900130.html

  {
    "Number":1,
    "Reference":"赵先生-20241201",
    "Requestor":"赵先生",
    "User":"SIRZHAO",
    "CostCenter":"A",
    "ShippingInstructions":

     {
      "name":"赵先生",
      "Address":

       {
         "street":"第1街道",
         "city":"哈尔滨",
         "province":"黑龙江",
         "zipCode":150000,
         "country":"中国"
       },

      "Phone":
       [
         {
           "type":"固定电话",
           "number":"0451-86779817"

          }
       ]
     },
    "Special Instructions":"
平寄邮件",
    "LineItems":

     [
        {
         "ItemNumber":1,
         "Part":

          {
           "Description":"《哲学与社会——老年沉思录》",
           "UnitPrice":19.95,
           "UPCCode":43396040144
          },

         "Quantity":7.0
        },
        {

         "ItemNumber":2,
         "Part":

          {
           "Description":"《陈平原文集》",
           "UnitPrice":19.95,
           "UPCCode":43396040145
          },

         "Quantity":7.0
        },
        {
         "ItemNumber":3,
         "Part":

          {
           "Description":"《蘑菇猎人:探寻北美野生蘑菇的地下世界》",
           "UnitPrice":19.95,
           "UPCCode":12236101345

          },
         "Quantity":1.0
        },
        {
         "ItemNumber":4,
         "Part":

          {
           "Description":"《楼兰新史(增订本)》",
           "UnitPrice":19.95,
           "UPCCode":85391756323

          },
         "Quantity":8.0
        },
        {
         "ItemNumber":5,
         "Part":

          {
           "Description":"《人类思想发展史:关于古代近东思辨思想的讨论》",
           "UnitPrice":19.95,
           "UPCCode":13023009592

          },
         "Quantity":8.0
        },
        {
         "ItemNumber":6,
         "Part":

          {
           "Description":"《韩家往事》",
           "UnitPrice":19.95,
           "UPCCode":27616864451

          },
         "Quantity":8.0
        }
      ]
   }

    在之前的博客中介绍过的JSON_VALUE只能显示JSON第1层数据:

 SELECT JSON_VALUE (doc, '$.Number') NUM,
 JSON_VALUE (doc, '$.Reference') Ref,
 JSON_VALUE (doc, '$.Requestor') Requestor,
 JSON_VALUE (doc, '$.User') account_name,
 JSON_VALUE (doc, '$.CostCenter') CC,
 JSON_VALUE (doc, '$."Special Instructions"') SI
FROM j1 where id=1;

NUMREFREQUESTORACCOUNT_NAMECCSI
1赵先生-20241201赵先生SIRZHAOA平寄邮件

    “点层次表示法”("LineItems"."ItemNumber")不是JSON_VALUE/JSON_QUERY允许的语法。以下的语句无法显示第2层及更深层的数据包裹关系的数据(如下面的LI和LQ用 “点层次表示法”,均返回空值):

 SELECT JSON_VALUE (doc, '$.Number') NUM,
 JSON_VALUE (doc, '$.Reference') Ref,
 JSON_VALUE (doc, '$.Requestor') Requestor,
 JSON_VALUE (doc, '$.User') account_name,
 JSON_VALUE (doc, '$.CostCenter') CC,
 JSON_VALUE (doc, '$."Special Instructions"') SI,
 JSON_VALUE (doc, '$."LineItems"."ItemNumber"' ) LI,
 JSON_QUERY (doc, '$."LineItems"."Part"' ) LQ
FROM j1 where id=1;

NUM REF REQUESTOR ACCOUNT_NAME CC SI LI LQ
1 赵先生-20241201 赵先生 SIRZHAO A 平寄邮件    

2. JSON_TABLE运算符在内存中映射JSON数据为表结构:

    SQL/JSON 标准允许使用JSON_TABLE和NESTED PATH运算符来提取多层数据。上一层数据(比如:上面例子中红色Number键的值:“订单号1”) 被提取并传送到下一层甚至是下下一层数据(比如:上面例子中的银色的表示“订单号为1”的订单详情),从而组成有商业意义的“明细清单”表结构。
    因此,JSON_TABLE是看成解除一个级别数据嵌套的运算符。而NESTED PATH则实现了“嵌套列”钻探。JSON_TABLE一次只能解除一个层次的数据包裹(嵌套),配合NESTED PATH(甚至嵌套的NESTED PATH)逐层向下级层次钻探,以解除更多级别的数据嵌套。
    以下的例子利用上面所介绍的知识,来构造结果集: 显示订单号1和该订单的明细:

SELECT d.* FROM j1 j,
                             JSON_TABLE (
                                                     j.doc,'$'                                             
                                                     COLUMNS (
                                                                        unumber NUMBER(10) PATH '$.Number',
                                                                        NESTED PATH '$.ShippingInstructions[*]' COLUMNS (
                                                                                                                                                        name VARCHAR2(14 CHAR) PATH '$.name' ,
                                                                                                                                                        NESTED PATH '$.Address[*]' COLUMNS (
                                                                                                                                                                                                                       street VARCHAR2(14 CHAR) PATH '$.street'
                                                                                                                                                                                                                      )
                                                                                                                                                       ),                                                                      
                                                                        NESTED PATH '$.LineItems[*]' COLUMNS (
                                                                                                                                         itemno NUMBER(16) PATH '$.ItemNumber',
                                                                                                                                         upccode VARCHAR2(14) PATH '$.Part.UPCCode',
                                                                                                                                         pdescription VARCHAR2(2000) PATH '$.Part.Description',

                                                                                                                                         price VARCHAR2(16) PATH '$.Part.UnitPrice'
                                                                                                                                        )
                                                                     )
                                                ) d
WHERE JSON_VALUE(doc, '$.User')='SIRZHAO';




UNUMBERNAMESTREETITEMNOUPCCODEPDESCRIPTIONPRICE
1赵先生第1街道    
1  143396040144《哲学与社会——老年沉思录》19.95
1  243396040145《陈平原文集》19.95
1  312236101345《蘑菇猎人:探寻北美野生蘑菇的地下世界》19.95
1  485391756323《楼兰新史(增订本)》19.95
1  513023009592《人类思想发展史:关于古代近东思辨思想的讨论》19.95
1  627616864451《韩家往事》19.95

   上面的COLUMNS,构造出第一层包裹关系中的数据列“UNUMBER”,其他列则由NESTED PATH COLUMNS句构造

SELECT d.* FROM j1 j,
                             JSON_TABLE (
                                                     j.doc,'$'                                             
                                                     COLUMNS (
                                                                        unumber NUMBER(10) PATH '$.Number',
                                                                        ......

                                                                     )
                                                ) d
WHERE JSON_VALUE(doc, '$.User')='SIRZHAO';




UNUMBER





1





1





1





1





1





1





1






     NESTED PATH COLUMNS句还可以嵌套:

SELECT d.* FROM j1 j,
                             JSON_TABLE (
                                                     j.doc,'$'                                             
                                                     COLUMNS (
                                                                        unumber NUMBER(10) PATH '$.Number',
                                                                        NESTED PATH '$.ShippingInstructions[*]' COLUMNS (
                                                                                                                                                        name VARCHAR2(14 CHAR) PATH '$.name' ,
                                                                                                                                                        NESTED PATH '$.Address[*]' COLUMNS (
                                                                                                                                                                                                                       street VARCHAR2(14 CHAR) PATH '$.street'
                                                                                                                                                                                                                      )
                                                                                                                                                       ),                                                                      
......                                                                     

    第1个NESTED PATH和COLUMNS之间 '$.ShippingInstructions[*]'代表了以下这个数组:

 
    "ShippingInstructions":

     {
      "name":"赵先生",
      "Address":

       {
         "street":"第1街道",
         "city":"哈尔滨",
         "province":"黑龙江",
         "zipCode":150000,
         "country":"中国"
       },

      "Phone":
       [
         {
           "type":"固定电话",
           "number":"0451-86779817"

          }
       ]
     },
 


    第2个NESTED PATH和COLUMNS之间'$.Address[*]'代表了以下这个小一点的数组:

 
      "Address":

       {
         "street":"第1街道",
         "city":"哈尔滨",
         "province":"黑龙江",
         "zipCode":150000,
         "country":"中国"
       },

  


    分析到此处,可以看出:JSON_TABLE行源使用NESTED PATH子句展平了多层嵌套数据。

3.   “点层次表示法”是JSON_TABLE允许的语法,但是如果有多个同级别的数据嵌套并存时, 必须使用NESTED PATH展平这些多层嵌套数据

     “点层次表示法”是JSON_TABLE允许的语法。如下这样写,结果集与本博客第2节的查询结果完全相同:

SELECT d.* FROM j1 j,
                             JSON_TABLE (
                                                     j.doc,'$'                                             
                                                     COLUMNS (
                                                                        unumber NUMBER(10) PATH '$.Number',
                                                                        NESTED PATH '$.ShippingInstructions[*]' COLUMNS (
                                                                                                                                                        name VARCHAR2(14 CHAR) PATH '$.name' ,
                                                                                                                                                        street VARCHAR2(104 CHAR) PATH '$.Address.street'                                                                   
                                                                                                                                                       ),                                                                      
                                                                        NESTED PATH '$.LineItems[*]' COLUMNS (
                                                                                                                                         itemno NUMBER(16) PATH '$.ItemNumber',
                                                                                                                                         upccode VARCHAR2(14) PATH '$.Part.UPCCode',
                                                                                                                                         pdescription VARCHAR2(2000) PATH '$.Part.Description',
                                                                                                                                     
    price VARCHAR2(16) PATH '$.Part.UnitPrice'
                                                                                                                                       )
                                                                     )
                                                ) d
WHERE JSON_VALUE(doc, '$.User')='SIRZHAO';




UNUMBERNAMESTREETITEMNOUPCCODEPDESCRIPTIONPRICE
1赵先生第1街道    
1  143396040144《哲学与社会——老年沉思录》19.95
1  243396040145《陈平原文集》19.95
1  312236101345《蘑菇猎人:探寻北美野生蘑菇的地下世界》19.95
1  485391756323《楼兰新史(增订本)》19.95
1  513023009592《人类思想发展史:关于古代近东思辨思想的讨论》19.95
1  627616864451《韩家往事》19.95

   其中的 “点层次表示法”:   

 street VARCHAR2(104 CHAR) PATH '$.Address.street'                                                    

   代表以下数据   

 "street":"第1街道",                                                  

  
但是如果有多个同级别的数据嵌套并存时, 必须使用NESTED PATH展平多层嵌套数据,以下这样使用 “点层次表示法”是错误的(没有形成“明细清单”结果集)

SELECT d.* FROM j1 j,
                             JSON_TABLE (
                                                     j.doc,'$'                                             
                                                     COLUMNS (
                                                                        unumber NUMBER(10) PATH '$.Number',
                                                                        name VARCHAR2(14 CHAR) PATH '$.ShippingInstructions.name' ,
                                                                        street VARCHAR2(104 CHAR) PATH '$.ShippingInstructions.Address.street',       
                                                                        itemno NUMBER(16) PATH '$.LineItems.ItemNumber',
                                                                        upccode VARCHAR2(14) PATH '$.LineItems.Part.UPCCode',
                                                                        pdescription VARCHAR2(2000) PATH '$.LineItems.Part.Description',
                                                                       
price VARCHAR2(16) PATH '$.Part.UnitPrice'
                                                                     )
                                                ) d
WHERE JSON_VALUE(doc, '$.User')='SIRZHAO';

Table created.




UNUMBERNAMESTREETITEMNOUPCCODEPDESCRIPTIONPRICE
1赵先生第1街道    

    这是因为 '$.LineItems.ItemNumber'是多个同级别的数据嵌套并存结构。比如:"ItemNumber":1"ItemNumber":2"ItemNumber":3"ItemNumber":4"ItemNumber":5"ItemNumber":6。




路过

雷人

握手

鲜花

鸡蛋

QQ|手机版|Bo's Oracle Station   

GMT+8, 2025-1-17 21:21 , Processed in 0.034422 second(s), 21 queries .

返回顶部