【问题标题】:Postgresql update JSONB object to arrayPostgresql 将 JSONB 对象更新为数组
【发布时间】:2020-12-09 14:00:35
【问题描述】:

我不知道为什么,但可能 PHP 将我的一些数据作为对象持久化,其中一些作为数组持久化。我的桌子看起来像:

seller_info_address 表:

 ID (INT)  |  address (JSONB)                                  |
------------+--------------------------------------------------|
     1      | {"addressLines":{"0":"Technology Park",...},...} |
     2      | {"addressLines":["Technology Park",...],...}     |

一些地址线是对象:

{
  "addressLines": {
    "0": "Technology Park",
    "1": "Blanchard Road",
    "3": "Dublin",
    "4": "2"
  },
  "companyName": "...",
  "emailAddress": [],
  "...": "..."
}

一些addressLines是数组:

{
  "addressLines": [
    "Technology Park",
    "Blanchard Road",
    "Dublin",
    "2"
  ],
  "companyName": "...",
  "emailAddress": [],
  "...": "..."
}

我想用 SQL 查询来平衡数据,但我不知道该怎么做。所有作为对象持久化的addressLines都应该更新为数组形式。

感谢您的帮助,谢谢!

【问题讨论】:

  • 我刚刚遇到了同样的问题,来这里是为了清理数据。您的数据有时是数组,有时是对象的原因是因为 php 数组必须基于 0 才能被视为数组。见stackoverflow.com/a/66644255/3790921

标签: sql jsonb postgresql-10


【解决方案1】:

您可以使用以下方法将对象转换为数组:

select id, (select jsonb_agg(e.val order by e.key::int) 
            from jsonb_each(sia.address -> 'addressLines') as e(key,val))
from seller_info_address sia
where jsonb_typeof(address -> 'addressLines') = 'object'

where 条件确保我们只对非数组的地址行执行此操作。

所使用的聚合也可以在 UPDATE 语句中使用:

update seller_info_address
  set address = jsonb_set(address, '{addressLines}', 
                          (select jsonb_agg(e.val order by e.key::int) 
                           from jsonb_each(address -> 'addressLines') as e(key,val))
                          )
where jsonb_typeof(address -> 'addressLines') = 'object';

【讨论】:

  • 令人着迷,几乎同时使用相同的解决方案。我想我们是灵魂伴侣。谢谢您的麻烦!
【解决方案2】:

好的,我现在自己找到了解决方案。绝对不是最有说服力的解决方案。我敢肯定有一个更好,更高效的,但它的工作......

DROP FUNCTION update_address_object_to_array(id INTEGER);
CREATE OR REPLACE FUNCTION
    update_address_object_to_array(id INTEGER)
    RETURNS VOID AS
$UPDATE_ADDRESS_OBJECT_TO_ARRAY$
BEGIN
    UPDATE seller_info_address
    SET address = jsonb_set(address, '{addressLines}', (
        SELECT CASE
                   WHEN jsonb_agg(addressLines) IS NOT NULL THEN jsonb_agg(addressLines)
                   ELSE '[]'
               END
        FROM seller_info_address sia,
             jsonb_each(address #> '{addressLines}') as t(key, addressLines)
        WHERE jsonb_typeof(sia.address -> 'addressLines') = 'object'
          AND seller_info_id = update_address_object_to_array.id
    ), true)
    WHERE seller_info_id = update_address_object_to_array.id
      AND jsonb_typeof(address -> 'addressLines') = 'object';
END
$UPDATE_ADDRESS_OBJECT_TO_ARRAY$
    LANGUAGE 'plpgsql';
SELECT update_address_object_to_array(sia.seller_info_id)
  FROM seller_info_address sia
 WHERE jsonb_typeof(address -> 'addressLines') = 'object';

内部 SELECT 使用 jsonb_each 获取 addressLines 对象中的所有行,然后使用 jsonb_agg 将它们聚合到一个数组中。条件表达式是为了防止出现空值。

然后将结果通过jsonb_set 存储在 UPDATE 中到 json 中所需的位置。 WHERES 应该是不言自明的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多