将JSON解压缩为平面格式

时间:2019-08-14 14:16:02

标签: json postgresql

我具有类似于以下内容的JSON:

{
    "ANNOTATIONS": [
    {
    "Label": "CommingledProduct",
    "Text": "NBP"
    },
    {
    "Label": "CommingledVenue",
    "Text": "OTC"
    }
    ]
}

我需要将其解压缩到带有与注释标签匹配的列的平面表中。因此,基于上述json的列将变为:

  • comingled_product
  • comingled_venue

JSON来自源表中的json字段,并被解压缩到另一个表中。

我知道我可以编写如下代码:

INSERT INTO my_target_table (comingled_product, comingled_venue)
SELECT
  payload->'ANNOTATIONS'->0->>'Text',
  payload->'ANNOTATIONS'->1->>'Text'
FROM my_source_table;

但是,我宁愿不使用注释的序数。我希望使用一些语法来镜像下面的伪代码:

INSERT INTO my_target_table (comingled_product, comingled_venue)
SELECT
  payload->'ANNOTATIONS'->'label="ComingledProduct"'->>'Text',
  payload->'ANNOTATIONS'->'label="ComingledVenueID"'->>'Text'
FROM my_source_table;

有人可以告诉我我正在尝试的方法是否可行以及如何做到?我在样本中包含的注释不止两个,因此涉及多个联接的任何事情可能都是不可行的。

使用PostGres 10.7

2 个答案:

答案 0 :(得分:2)

demo:db<>fiddle

WITH cte AS (
    SELECT 
        elems.value
    FROM 
        my_source_table,
        json_array_elements(payload -> 'ANNOTATIONS') elems
)
SELECT 
    (SELECT value ->> 'Text' FROM cte WHERE value ->> 'Label' = 'CommingledProduct'),
    (SELECT value ->> 'Text' FROM cte WHERE value ->> 'Label' = 'CommingledVenue')
  1. 将数组扩展为每个数组元素一行,并将此结果存储以供CTE进一步使用
  2. 此结果可用于查询期望值(无需进行两次扩展)

可能会快一点:

demo:db<>fiddle

SELECT
    payload,
    MIN(the_text) FILTER (WHERE label = 'CommingledProduct'),
    MIN(the_text) FILTER (WHERE label = 'CommingledVenue')
FROM (
    SELECT 
        payload::text AS payload,
        elems ->> 'Label' AS label,
        elems ->> 'Text' AS the_text
    FROM 
        my_source_table,
        json_array_elements(payload -> 'ANNOTATIONS') elems
) s
GROUP BY payload

答案 1 :(得分:2)

@ S-Man的答案很好,您应该将其用于postgres 10.7。 json_path将添加到postgres 12中,这将使您可以做一些更接近伪代码的操作,但只能使用jsonb(而不是json):

INSERT INTO my_target_table (comingled_product, comingled_venue)
SELECT jsonb_path_query(payload, 
          '$.ANNOTATIONS[*] ? (@.Label == "CommingledProduct")')->>'Text', 
       jsonb_path_query(payload, 
          '$.ANNOTATIONS[*] ? (@.Label == "CommingledVenue")')->>'Text' 
FROM my_source_table;

jsonb_path_query语法需要一点时间来弄清楚,但它基本上是返回ANNOTATIONS数组的元素,其Label等于CommingledProduct或CommingledVenue。 jsonb_path_query返回一个jsonb对象,因此我们可以使用->>运算符从该对象获取'Text'的值。