PostgreSQL:根据 JSON 数组中 JSON 的值对行进行排序
PostgreSQL: Sorting the rows based on value of a JSON in an array of JSON
A table 说 products
有一个名为 identifiers
的 JSONB 列,它存储 JSON 个对象的数组。
产品中的示例数据
id | name | identifiers
-----|-------------|---------------------------------------------------------------------------------------------------------------
1 | umbrella | [{"id": "productID-umbrella-123", "domain": "ecommerce.com"}, {"id": "amzn-123", "domain": "amzn.com"}]
2 | ball | [{"id": "amzn-234", "domain": "amzn.com"}]
3 | bat | [{"id": "productID-bat-234", "domain": "ecommerce.com"}]
现在,我必须编写一个查询,根据域“amzn.com”
的“id”值对 table 中的元素进行排序
预期结果
id | name | identifiers
----- |--------------|---------------------------------------------------------------------------------------------------------------
3 | bat | [{"id": "productID-bat-234", "domain": "ecommerce.com"}]
1 | umbrella | [{"id": "productID-umbrella-123", "domain": "ecommerce.com"}, {"id": "amzn-123", "domain": "amzn.com"}]
2 | ball | [{"id": "amzn-234", "domain": "amzn.com"}]
amzn.com
的 ID 是“amzn-123”和“amzn-234”。
当按 amzn.com 的 id 排序时,首先出现“amzn-123”,然后是“amzn-234”
按域“amzn.com”的“id”值对 table 进行排序,
id 为 3 的记录首先出现,因为 amzn.com 的 id 为 NULL,
后跟 ID 为 1 和 2 的记录,该记录具有已排序的有效 ID。
我真的不知道如何为这个用例编写查询。
如果它是 JSONB 而不是 JSON 的数组,我会尝试的。
是否可以在 PostgreSQL 中为此类用例编写查询?
如果是,请至少给我一个伪代码或粗略的查询。
由于您不知道数组中的位置,因此您需要遍历所有数组元素以找到亚马逊 ID。
获得 ID 后,您可以将其与 order by
一起使用。使用 nulls first
将那些没有亚马逊 ID 的产品放在顶部。
select p.*, a.amazon_id
from products p
left join lateral (
select item ->> 'id' as amazon_id
from jsonb_array_elements(p.identifiers) as x(item)
where x.item ->> 'domain' = 'amzn.com'
limit 1 --<< safe guard in case there is more than one amazon id
) a on true --<< we don't really need a join condition
order by a.amazon_id nulls first;
对于 Postgres 12,这会更短一些:
select p.*
from products p
order by jsonb_path_query_first(identifiers, '$[*] ? (@.domain == "amzn.com").id') nulls first
经过一些调整,这是最终成功的查询,
select p.*, amzn -> 'id' AS amzn_id
from products p left join lateral JSONB_ARRAY_ELEMENTS(p.identifiers) amzn ON amzn->>'domain' = 'amzn.com'
order by amzn_id nulls first
A table 说 products
有一个名为 identifiers
的 JSONB 列,它存储 JSON 个对象的数组。
产品中的示例数据
id | name | identifiers
-----|-------------|---------------------------------------------------------------------------------------------------------------
1 | umbrella | [{"id": "productID-umbrella-123", "domain": "ecommerce.com"}, {"id": "amzn-123", "domain": "amzn.com"}]
2 | ball | [{"id": "amzn-234", "domain": "amzn.com"}]
3 | bat | [{"id": "productID-bat-234", "domain": "ecommerce.com"}]
现在,我必须编写一个查询,根据域“amzn.com”
的“id”值对 table 中的元素进行排序预期结果
id | name | identifiers
----- |--------------|---------------------------------------------------------------------------------------------------------------
3 | bat | [{"id": "productID-bat-234", "domain": "ecommerce.com"}]
1 | umbrella | [{"id": "productID-umbrella-123", "domain": "ecommerce.com"}, {"id": "amzn-123", "domain": "amzn.com"}]
2 | ball | [{"id": "amzn-234", "domain": "amzn.com"}]
amzn.com
的 ID 是“amzn-123”和“amzn-234”。
当按 amzn.com 的 id 排序时,首先出现“amzn-123”,然后是“amzn-234”
按域“amzn.com”的“id”值对 table 进行排序, id 为 3 的记录首先出现,因为 amzn.com 的 id 为 NULL, 后跟 ID 为 1 和 2 的记录,该记录具有已排序的有效 ID。
我真的不知道如何为这个用例编写查询。 如果它是 JSONB 而不是 JSON 的数组,我会尝试的。
是否可以在 PostgreSQL 中为此类用例编写查询? 如果是,请至少给我一个伪代码或粗略的查询。
由于您不知道数组中的位置,因此您需要遍历所有数组元素以找到亚马逊 ID。
获得 ID 后,您可以将其与 order by
一起使用。使用 nulls first
将那些没有亚马逊 ID 的产品放在顶部。
select p.*, a.amazon_id
from products p
left join lateral (
select item ->> 'id' as amazon_id
from jsonb_array_elements(p.identifiers) as x(item)
where x.item ->> 'domain' = 'amzn.com'
limit 1 --<< safe guard in case there is more than one amazon id
) a on true --<< we don't really need a join condition
order by a.amazon_id nulls first;
对于 Postgres 12,这会更短一些:
select p.*
from products p
order by jsonb_path_query_first(identifiers, '$[*] ? (@.domain == "amzn.com").id') nulls first
经过一些调整,这是最终成功的查询,
select p.*, amzn -> 'id' AS amzn_id
from products p left join lateral JSONB_ARRAY_ELEMENTS(p.identifiers) amzn ON amzn->>'domain' = 'amzn.com'
order by amzn_id nulls first