问题描述
一个表说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”值对表中的元素进行排序
预期结果
id | name | identifiers
----- |--------------|---------------------------------------------------------------------------------------------------------------
3 | bat | [{"id": "productID-bat-234","domain": "ecommerce.com"}]
1 | umbrella | [{"id": "productID-umbrella-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”值对表格进行排序, 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