【问题标题】:ERROR: cannot call json_array_elements on a non-array错误:无法在非数组上调用 json_array_elements
【发布时间】:2021-10-12 13:32:06
【问题描述】:

我有一个 Postgres 查询,它返回以下值。此查询返回 id 的一个数据。

select h ->> 'dw:address_line_1' as address, h ->> 'dw:city' as city, h -> 'dw:region' -> 'dw:ID' -> 2 -> '#text' as state, h ->'dw:Country_ISO_Code' as country
from testschema.dw_data_job t, json_array_elements(t.addresses::json) h
where t.id = '12345'
and h -> 'dw:address_type' -> 'dw:ID' -> 1 ->> '#text' = 'BUSINESS'

现在我想在表dw_data_job 中获取整个人口的商业地址。我将查询更改为如下。

select h ->> 'dw:address_line_1' as address, h ->> 'dw:city' as city, h -> 'dw:region' -> 'dw:ID' -> 2 -> '#text' as state, h ->'dw:Country_ISO_Code' as country
from testschema.dw_data_job t, testschema.dw_data_demo t1, json_array_elements(t.addresses::json) h
where t.id = t1.id
and h -> 'dw:address_type' -> 'dw:ID' -> 1 ->> '#text' = 'BUSINESS' 

现在我得到如下错误

ERROR:  cannot call json_array_elements on a non-array
CONTEXT:  parallel worker
SQL state: 22023

dw_data_job.addresses 列的类型为text,数据如下所示 - 当 JSON 值为 数组 时:

[{"dw:address_line_1": "123 Inter Pkwy", "dw:city": "Richardson", "dw:region": {"@dw:Descriptor": "Texas", "dw:ID": [{"@dw:type": "WID", "#text": "fc77e3a1ab36487f9646d14f7242dd77"}, {"@dw:type": "Country_Region_ID", "#text": "USA-TX"}, {"@dw:type": "ISO_3166-2_Code", "#text": "TX"}]}, "dw:region_subdivision_1": "Dallas", "dw:postal_code": "75081", "dw:Country_ISO_Code": "USA", "dw:address_type": {"@dw:Descriptor": "Business", "dw:ID": [{"@dw:type": "WID", "#text": "4fae289a7fe541b098ca9448e462ff6b"}, {"@dw:type": "Communication_Usage_Type_ID", "#text": "BUSINESS"}]}, "dw:primary": "1"}, {"dw:address_line_1": "567 South Dr", "dw:city": "Plano", "dw:region": {"@dw:Descriptor": "Texas", "dw:ID": [{"@dw:type": "WID", "#text": "fc77e3a1ab36487f9646d14f7242dd77"}, {"@dw:type": "Country_Region_ID", "#text": "USA-TX"}, {"@dw:type": "ISO_3166-2_Code", "#text": "TX"}]}, "dw:region_subdivision_1": "Collin", "dw:postal_code": "75024", "dw:Country_ISO_Code": "USA", "dw:address_type": {"@dw:Descriptor": "Home", "dw:ID": [{"@dw:type": "WID", "#text": "836cf00ef5974ac08b786079866c946f"}, {"@dw:type": "Communication_Usage_Type_ID", "#text": "HOME"}]}, "dw:primary": "1"}, {"dw:address_line_1": "789 North Dr.", "dw:city": "Plano", "dw:region": {"@dw:Descriptor": "Texas", "dw:ID": [{"@dw:type": "WID", "#text": "fc77e3a1ab36487f9646d14f7242dd77"}, {"@dw:type": "Country_Region_ID", "#text": "USA-TX"}, {"@dw:type": "ISO_3166-2_Code", "#text": "TX"}]}, "dw:region_subdivision_1": "Collin", "dw:postal_code": "75024", "dw:Country_ISO_Code": "USA", "dw:address_type": {"@dw:Descriptor": "Home-Vac", "dw:ID": [{"@dw:type": "WID", "#text": "836cf00ef5974ac08b786079866c946f"}, {"@dw:type": "Communication_Usage_Type_ID", "#text": "HOME-VAC"}]}, "dw:communication_usage_behavior": {"@dw:Descriptor": "Mailing", "dw:ID": [{"@dw:type": "WID", "#text": "bea4505497c901ea53792e2628077617"}, {"@dw:type": "Communication_Usage_Behavior_Tenanted_ID", "#text": "MAILING"}]}, "dw:primary": "0"}]

另一个带有非数组(对象)的样本值:

{"dw:address_line_1": "123 Local Pkwy", "dw:city": "Cary", "dw:region": {"@dw:Descriptor": "North Carolina", "dw:ID": [{"@dw:type": "WID", "#text": "1486a0a4a8464c3b9ec482d4038deb99"}, {"@dw:type": "Country_Region_ID", "#text": "USA-NC"}, {"@dw:type": "ISO_3166-2_Code", "#text": "NC"}]}, "dw:region_subdivision_1": "Wake", "dw:postal_code": "27513", "dw:Country_ISO_Code": "USA", "dw:address_type": {"@dw:Descriptor": "Business", "dw:ID": [{"@dw:type": "WID", "#text": "4fae289a7fe541b098ca9448e462ff6b"}, {"@dw:type": "Communication_Usage_Type_ID", "#text": "BUSINESS"}]}, "dw:primary": "1"}

查询需要同时容纳数组和非数组 json 数据,以返回嵌套键 #text 具有值 'BUSINESS' 的所有数据行的地址、城市、州和国家/地区代码。

【问题讨论】:

  • 错误消息告诉您“地址”并不总是看起来像那样。你可以使用json_typeof(t.addresses::json) 来查找那些没有的。
  • 谢谢阿德里安。函数 json_typeof() 以字符串形式返回最外层 JSON 值的类型。但我想遍历 t.addresses::json 的每个 json 数组元素。所有地址都以 [ 开头并以 ] 结尾。基于此,我们总是每行至少有一个元素。
  • 对于您向我们展示的示例, json_typeof(t.addresses::json) 肯定不是“字符串”。它是'数组'。 dbfiddle.uk/…
  • "Potgres" 可能会更轻松,但 Postgres 对错误是认真的。 ;)
  • 谢谢 Jeff 和 Erwin,我正在尝试组合一个从数组和非数组中提取 BUSINESS 地址的查询。

标签: sql arrays json postgresql


【解决方案1】:

就像错误消息告诉您的那样(并且 Jeff 指出),表 dw_data_job 中有一行或多行,其中列 addresses 不包含有效的 JSON 数组(或 NULL)。一个有效的 JSON 文字,是的,否则我们会看到由失败的转换为 ::json 引发的不同错误消息,但不是 JSON array

运行此查询以识别违规行:

SELECT id, addresses
     , jsonb_pretty(addresses::jsonb) AS js_pretty  -- optional
FROM   dw_data_job
WHERE  json_typeof(addresses::json) IS DISTINCT FROM 'array';

(在addresses 中包含NULL 值,这不会引发报告的错误,但也可能是个问题。)

要跳过包含无效数据的行并继续查询:

SELECT h ->> 'dw:address_line_1' AS address
     , h ->> 'dw:city' AS city
     , h #>> '{dw:region,dw:ID,2,#text}' AS state
     , h ->> 'dw:Country_ISO_Code' AS country
     , json_typeof(t.addresses::json)
FROM   testschema.dw_data_job t
JOIN   testschema.dw_data_demo t1 USING (id)
CROSS  JOIN json_array_elements(t.addresses::json) h
WHERE  json_typeof(t.addresses::json) = 'array'
AND    h #>> '{dw:address_type,dw:ID,1,#text}' = 'BUSINESS';

我使用紧凑运算符 #> 简化了深层嵌套值的语法,并返回所有 text 而不是一些 json(作为有根据的猜测)。

要包含普通对象和数组,您可以:

WITH sel AS (  -- compute json & type
   SELECT t.addresses::json AS a, json_typeof(t.addresses::json) AS js_type
   FROM   testschema.dw_data_job t
   JOIN   testschema.dw_data_demo t1 USING (id)
   )
 , obj AS (  -- unnest arrays and union with plain objects
   SELECT json_array_elements(a) AS h FROM sel WHERE js_type = 'array'
   UNION ALL
   SELECT a                           FROM sel WHERE js_type = 'object'
   -- all other types are ignored!
   )
SELECT h ->> 'dw:address_line_1' AS address
     , h ->> 'dw:city' AS city
     , h #>> '{dw:region,dw:ID,2,#text}' AS state
     , h ->> 'dw:Country_ISO_Code' AS country
FROM   obj
WHERE  h #>> '{dw:address_type,dw:ID,1,#text}' = 'BUSINESS';

db小提琴here

【讨论】:

  • 谢谢欧文,现在我明白了。给定非数组和数组两种类型的场景,如何在一次查询中提取业务地址?谢谢
  • @BalajiUppalapati:请在问题中澄清这一点。明确目标,提供您的 Postgres 版本和与之配套的示例数据 - 包括。包含非数组数据的行。
  • 我在原始帖子中添加了非数组 json 数据。查询需要同时容纳数组和非数组 json 数据,这些数据为#text BUSINESS 的所有数据行返回地址1、城市、州和国家/地区代码
  • @BalajiUppalapati:考虑添加的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多