在JSON数组上使用Oracle Path Expressions

时间:2017-12-06 16:44:39

标签: oracle12c jsonpath

我正在尝试使用针对Oracle JSON数据结构的路径表达式编写一个简单查询,该结构将返回学生姓名及其CS220教师的姓名(如果他们正在学习该课程)。

JSON:

{
  'studentName': 'John Smith',
  'classes': [
    {
      'className': 'CS115',
      'teacherName': 'Sally Wilson'
    },
    {
      'className': 'CS220',
      'teacherName': 'Jason Wu'
    }
  ]
}

预期产出

Student Name      Professor
John Smith        Jason Wu
Jane Doe                             << Not taking CS220
Ajay Kumar        Robert Kroll

我希望写的查询:

Select 
    jsonfield.studentName,
    jsonfield.classes.<some path expression to find the CS220 professor here>
from mytable

我找到的唯一解决方案是将嵌套的“类”投影到表中,并将其连接到上面的查询以获取教授。我原以为Oracle的json路径实现能够在没有第二个查询的开销/复杂性的情况下解决这个问题。

1 个答案:

答案 0 :(得分:2)

在12cR1中,您可以执行以下操作:

select jt.studentname,
  max(case when jt.classname = 'CS220' then jt.teachername end) as teachername
from mytable mt
cross join json_table (
  mt.jsonfield,
  '$'
  columns (
    studentname varchar2(30) path '$.studentName',
    nested path '$.classes[*]' columns (
      classname varchar2(30) path '$.className',
      teachername varchar2(30) path '$.teacherName'
    )
  )
) jt
group by jt.studentname;

json_table()将JSON拆分为关系列; nested path表示每个班级(每个学生)获得一行,并附有相关的班级名称和教师姓名。

然后,选择列表使用案例表达式将教师名称更改为任何其他类的null - 因此John Smith获得一行CS220和Jason Wu,以及一行CS115和null。将max()create table mytable (jsonfield clob check (jsonfield is json)); insert into mytable a(jsonfield) values (q'#{ 'studentName': 'John Smith', 'classes': [ { 'className': 'CS115', 'teacherName': 'Sally Wilson' }, { 'className': 'CS220', 'teacherName': 'Jason Wu' } ] }#'); insert into mytable a(jsonfield) values (q'#{ 'studentName': 'Jane Doe', 'classes': [ { 'className': 'CS115', 'teacherName': 'Sally Wilson' } ] }#'); insert into mytable a(jsonfield) values (q'#{ 'studentName': 'Ajay Kumar', 'classes': [ { 'className': 'CS220', 'teacherName': 'Robert Kroll' } ] }#'); 聚合在一起会使所有不相关的教师都被忽略。

使用一些扩展的样本数据:

json_table()

基本select jt.*, case when jt.classname = 'CS220' then jt.teachername end as adjusted_teachername from mytable mt cross join json_table ( mt.jsonfield, '$' columns ( studentname varchar2(30) path '$.studentName', nested path '$.classes[*]' columns ( classname varchar2(30) path '$.className', teachername varchar2(30) path '$.teacherName' ) ) ) jt; STUDENTNAME CLASSNAME TEACHERNAME ADJUSTED_TEACHERNAME ------------------------------ ------------------------------ ------------------------------ ------------------------------ John Smith CS115 Sally Wilson John Smith CS220 Jason Wu Jason Wu Jane Doe CS115 Sally Wilson Ajay Kumar CS220 Robert Kroll Robert Kroll 来电:

select jt.studentname,
  max(case when jt.classname = 'CS220' then jt.teachername end) as teachername
from mytable mt
cross join json_table (
  mt.jsonfield,
  '$'
  columns (
    studentname varchar2(30) path '$.studentName',
    nested path '$.classes[*]' columns (
      classname varchar2(30) path '$.className',
      teachername varchar2(30) path '$.teacherName'
    )
  )
) jt
group by jt.studentname;

STUDENTNAME                    TEACHERNAME                  
------------------------------ ------------------------------
John Smith                     Jason Wu                      
Jane Doe                                                     
Ajay Kumar                     Robert Kroll                  

添加聚合步骤:

select jt.*
from mytable mt
cross join json_table (
  mt.jsonfield,
  '$'
  columns (
    studentname varchar2(30) path '$.studentName',
    nested path '$.classes[*]?(@.className=="CS220")' columns (
      teachername varchar2(30) path '$.teacherName'
    )
  )
) jt;

在12cR2中我 想想想到你可能会做这样的事情,在JSON路径中有一个过滤器(在12cR1中不允许这样做) ):

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css">
 
 <div>
  <span class="icon">
    <i class="fa fa-home"></i>
  </span>
  <span>ICON</span>
 </div>

...但我没有合适的数据库来测试它。

...但事实证明,获得&#34; ORA-40553:此操作中不支持谓词的路径表达式&#34;和&#34;只有JSON_EXISTS支持谓词&#34;。