【问题标题】:How to process json data and put it into arrays in postgresqlpostgresql中如何处理json数据并放入数组
【发布时间】:2021-08-06 03:41:56
【问题描述】:

我有一个包含两列的 postgresql 表。名称 VARCHAR(255) 并注释 JSON。示例数据集可能如下所示:

| name      | notes                            |
|-----------|----------------------------------|
| 'anna'    | {'link_to': ['bob']}             |
| 'bob'     | {'link_to': ['anna', 'claudia']} |
| 'claudia' | {'link_to': []}                  |

现在我想做两件事。

  1. 将来自'link_to' 的json 列表放入另一个名为referres_to 的列中(那么它必须是数组VARCHAR 类型)。以我为例:

    name notes referrals_to
    'anna' {'link_to': ['bob']} ['bob']
    'bob' {'link_to': ['anna', 'claudia']} ['anna', 'claudia']
    'claudia' {'link_to': []} []
  2. 创建另一个名为referres_from 的列,我想在其中存储引用了某个名称的所有名称。在我的例子中:

    name notes referrals_from
    'anna' {'link_to': ['bob']} ['bob']
    'bob' {'link_to': ['anna', 'claudia']} ['anna']
    'claudia' {'link_to': []} ['bob']

如何使用 postgresql 查询来做到这一点?我可以使用 python 轻松完成,但我猜这会比直接使用 postgresql 慢。

【问题讨论】:

    标签: sql json postgresql


    【解决方案1】:

    referrals_to 列可以使用-> 运算符提取数组。对于referrals_from 列,我将使用标量子选择将所有引用名称收集到单个列(JSON 数组)中

    select name, 
           notes, 
           notes -> 'link_to' as referrals_to,
           (select jsonb_agg(name)
            from the_table t2
            where t2.name <> t1.name
            and t2.notes -> 'link_to' ? t1.name) as referrals_from
    from the_table t1
    ;
    

    ? 运算符测试 JSON 数组是否包含特定字符串。在这种情况下,它会测试 link_to 数组是否包含来自外部查询的名称。

    Online Example

    假设 name 在您的表中是唯一的,您可以使用该查询来更新表中的新列:

    update the_table 
       set referrals_to = notes -> 'link_to', 
           referrals_from = t.referrals_from
    from (
      select t1.name, 
             (select jsonb_agg(name)
              from the_table t2
              where t2.name <> t1.name
              and t2.notes -> 'link_to' ? t1.name) as referrals_from
      from the_table t1
    ) t 
    where t.name = the_table.name;
    

    【讨论】:

    • 感谢您的回复,但我在这里没有看到 UPDATE 命令,如何将referrals_to 和referres_from 值存储在各自的列中?
    • @TomAtix:你没有在问题中提到 UPDATE 。你说你的表只包含两列
    • 可能我不是 100% 清楚。我的表最初有两列,我说我想“创建另一列 [使用 ALTER TABLE,我知道如何做] 来存储......”所以我说我想把这些信息放在列中。无论如何,如果你能更新你的答案来做到这一点,那就太好了,非常感谢。
    • “创建另一列”也可能意味着“在查询中创建另一列”。请参阅我的编辑。但是referrals_to 对我来说毫无意义,因为这正是notes 列中已经存在的信息。
    • 1) 感谢您的更新。 2) 我需要 Referrs_to 字段,因为我正在应用一些我不考虑的附加条件以保持简单。 3) 我需要稍微修改一下 setrefers_to 语句,因为格式与 postgres 数组不同。 4)我猜,referrals_from 更新语句有效,除此之外我需要先将 t2.notes -> 'link_to' 的格式转换为 JSONB,但它的效率非常低,因为它一遍又一遍地循环整个表对于每个条目。对于有一对夫妇的桌子,几分钟后它不会完成
    【解决方案2】:

    或多或少您在步骤中描述的内容:

    WItH cte AS (
      SELECT
        name,
        BTRIM(value:: text, '"') AS referrals
      FROM
        (
          SELECT
            name,
            foo.notes:: json - > > 'link_to' AS link_to
          FROM
            foo
        ) a
        left JOIN LATERAL json_array_elements (a.link_to:: json) ON TRUE
    )
    SELECT
      a1.name,
      array_to_json(array_agg(a1.referrals))
    FROM
      cte a1
      JOIN cte a2 ON a1.name = a2.referrals
    GROUP BY
      a1.name
    

    【讨论】:

    • 感谢您的回复,但我在这里看不到 UPDATE 命令,如何将referrals_to 和referres_from 值存储在各自的列中?
    • @TomAtix 您从未提及任何更新。此外,将其转换为更新语句应该很简单
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 2015-07-11
    • 2020-02-23
    • 1970-01-01
    • 2019-06-19
    • 2018-05-13
    相关资源
    最近更新 更多