JSON_TABLE筛选条件问题

时间:2019-11-12 15:49:39

标签: sql json oracle

我正在尝试使用JSON_TABLE将对象的JSON数组映射到关系表列。
Parts数组由指令数组的数组组成。每个指令数组都包含具有三个名称值对的一致名称的对象。名称字段的值始终为“系列”,“功能”或“价格”。这些在数组中并不总是保持一致的顺序。我以为我可以在columns子句中使用过滤条件,以将正确的值映射到正确的列。

WITH STR AS (
select 
'
{
  "Parts": [
    {
      "instruction": [
        {
          "name": "Family",
          "value": "AJE",
          "type": "0"
        },
        {
          "name": "Feature",
          "value": "AJKA",
          "type": "0"
        },
        {
          "name": "Price",
          "value": "0",
          "type": "0"
        }
      ]
    },
    {
      "instruction": [
        {
          "name": "Feature",
          "value": "AJKB",
          "type": "0"
        },
        {
          "name": "Family",
          "value": "AJA",
          "type": "0"
        }
      ]
    }
  ]
}
' JSTR
FROM DUAL)
SELECT JT.*
FROM STR SO,
JSON_TABLE(SO.JSTR, '$.Parts[*].instruction[*]'
           COLUMNS ("Family"  PATH '$."value"?(@.name == "Family" )',
                    "Feature" PATH '$."value"?(@.name == "Feature")',
                    "Price"   PATH '$."value"?(@.name == "Price")'
                    )
           )         
           AS "JT"

显示代码时,它返回五行,所有字段均为空。 我意识到上面的代码是错误的。下面是另一种尝试。这段代码将返回数据(注释掉过滤条件,并对数组索引进行硬编码),但是列数据映射错误。

JSON_TABLE(SO.JSTR, '$.Parts[*]' --ERROR ON ERROR
 COLUMNS ("Family"  PATH '$.instruction[0]."value"', --?(@.name == "Family" )
          "Feature" PATH '$.instruction[1]."value"', --?(@.name == "Feature")
          "Price"   PATH '$.instruction[2]."value"' --?(@.name == "Price")
                    )



Family   Feature   Price
------   -------   -----
AJE       AJKA      0
AJKA      AJE   



I'm trying to return this:
Family   Feature   Price
------   -------   -----
AJE      AJKA        0
AJA      AJKB

3 个答案:

答案 0 :(得分:0)

更新:ORD应该计算指令,而不是单个值。

要将所需的值放在右列中,请调整路径:

SELECT JT.*
FROM STR SO,
JSON_TABLE(
SO.JSTR, '$.Parts[*].instruction'
COLUMNS (
  ord for ordinality,
  nested path '$[*]' columns (
    Family path '$?(@.name == "Family").value',
    Feature path '$?(@.name == "Feature").value',
    Price path '$?(@.name == "Price").value'
    )
  )
)         
AS "JT";

ORD FAMILY FEATURE PRICE   
  1 AJE                           
  1        AJKA                
  1                    0        
  2        AJKB                
  2 AJA      

现在只需按ORD分组即可:

SELECT ord,
  max(family) family,
  max(feature) feature,
  max(price) price
FROM STR SO,
JSON_TABLE(
SO.JSTR, '$.Parts[*].instruction'
COLUMNS (
  ord for ordinality,
  nested path '$[*]' columns (
    Family path '$?(@.name == "Family").value',
    Feature path '$?(@.name == "Feature").value',
    Price path '$?(@.name == "Price").value'
    )
  )
)         
AS "JT"
group by ord
order by ord;

ORD FAMILY   FEATURE   PRICE   
  1 AJE      AJKA          0        
  2 AJA      AJKB

最好的问候,炖阿什顿

答案 1 :(得分:0)

一个选项是确定子查询中Ordinality的{​​{1}}值,该子查询将按NESTED PATH '$."Parts"[*]."instruction"[*]'列值分组的ROW_NUMBER()函数的排序和{{1} }通过namePivoting列:

Family

Demo

答案 2 :(得分:0)

我希望StackOverflow的人们会始终预先指出他们的Oracle数据库版本。

无论如何,此黑客似乎可以在18c版中使用:

SELECT ord,
  max(json_value(jt.Family, '$.value')) family,
  max(json_value(jt.Feature, '$.value')) feature,
  max(json_value(jt.Price, '$.value')) price
FROM STR SO,
JSON_TABLE(
SO.JSTR, '$.Parts[*].instruction'
COLUMNS (
  ord for ordinality,
  nested path '$[*]' columns (
    Family format json path '$?(@.name == "Family")',
    Feature format json path '$?(@.name == "Feature")',
    Price format json path '$?(@.name == "Price")'
    )
  )
)         
AS "JT"
group by ord
order by ord;

更好的解决方案是简化JSON并使用PIVOT子句操纵结果:

select family, feature, price
from (
  SELECT jt.ord, jt.name, jt.value
  from str,
  JSON_TABLE(
    str.JSTR, '$.Parts[*].instruction'
    COLUMNS (
      ord for ordinality,
      nested path '$[*]' columns (
        name varchar2(100) path '$.name',
        value varchar2(100) path '$.value'
      )
    )
  )
  AS "JT"
)
pivot(max(value) for name in ('Family' as Family, 'Feature' as Feature, 'Price' as Price))
order by ord;