Postgres检查JSON密钥

时间:2018-01-03 14:21:06

标签: sql json postgresql

我目前正在使用postgres数据库,但我的知识仅限于SQL。我正在使用订单数据库,需要选择购买了所选产品的所有客户。我的表格如下:

order_id      customer_name   products_ordered
1             a               {"apples":3, "pears":4}
2             b               {"apples":4, "pears":4, "oranges":2}
3             c               {"apples":2, "oranges":3}
4             a               {"apples": 5}
5             c               {"oranges": 4}
6             a               {"oranges":1}

我需要检查哪些客户在某个时候点了每个产品,苹果,梨和橙子,所以输出应该如下:

customer_name
a
b

我没有访问数据库中的JSON对象的经验,我想知道如何检索一些客户列表,这些客户在某些时候订购了 [key of keys]

提前致谢!

2 个答案:

答案 0 :(得分:1)

这不是最漂亮的查询,但它可以正常运作。

将json密钥解压缩到自己的记录中,按客户名聚合记录,然后进行包含数组的比较。有点滥用CTE来做这件事......

with
    __customer_products as(
        select
            customer_name,
            json_object_keys(products_ordered) as product_key
        from
            orders
    ),
    __customer_products_merged as(
        select
            customer_name,
            array_agg(product_key) as product_keys
        from
            __customer_products
        group by
            customer_name
    )
select
    customer_name
from
    __customer_products_merged
where
    product_keys @> array['apples', 'pears', 'oranges']

答案 1 :(得分:0)

如果您愿意创建一个自定义聚合函数,将多个JSONB值聚合为一个,并合并密钥,则可以使用简单查询执行此操作。

首先创建聚合函数:

create aggregate jsonb_object_agg(jsonb) 
(  
  sfunc = 'jsonb_concat',
  stype = jsonb,
  initcond = '{}'
);

请注意,这与内置jsonb_object_agg()不同,后者带有两个参数(键,值)。它使用jsonb_concat函数||将两个JSONB值合并为一个。

使用该聚合,您的查询就像:

一样简单
select customer_name
from orders
group by customer_name
having jsonb_object_agg(products_ordered) ?& array['pears','apples', 'oranges'];

?&运算符检查JSONB值中是否存在所有键。

如果没有聚合功能,您可以这样做:

select customer_name
from orders, 
     jsonb_each_text(products_ordered) as t(k,v)
group by customer_name
having jsonb_object_agg(t.k, t.v) ?& array['pears','apples', 'oranges'];

然而,这会将每个JSON值扩展为每个订单的多行,只是为了再次聚合 - 这会产生比“真实”聚合函数更大的中间结果,因此可能会更慢。

在线示例:http://rextester.com/EAZVG14239

以上所有内容均假设您的products_orderedJSONB列。如果是JSON列,则需要将其投放到JSONB