查询并统计jsonb列

时间:2016-02-15 18:34:14

标签: sql json postgresql jsonb

我是postgreSQL(9.5)Json世界的新手。寻找帮助编写此查询。以此简化表为例。

CREATE TABLE activity_log (uri varchar,
                           data jsonb );

'data'列内的数据示例。

"{"ListingInputFilterBean":{"searchItems": [], "listingStatus": "ACTIVE"}"

"{"ListingInputFilterBean":{"searchItems": [{"name": "Dachshund", "type": "BREED"}], "listingStatus": "ACTIVE"}}"

"{"ListingInputFilterBean":{"searchItems": [{"name": "Lab", "type": "BREED"}, {"name": "Black Lab", "type": "CST"}], "listingStatus": "ACTIVE"}}"

'data'列用于记录每个URI调用的特定数据集。在这种情况下,searchItems数组包含搜索中使用的项。我正在寻找一个查找最多搜索'品种'的查询。我想计算当'BREED'类型时使用每个'name'的次数。

我最初的方法是撤回每个'searchItems'。使用jsonb_to_recordset将它们变成行集,但是在阅读文档时我很快就抓住了(对不起,我是菜鸟)。

有关如何编写SQL的任何建议吗?

1 个答案:

答案 0 :(得分:0)

WITH log_activity(data) AS ( VALUES
  ('{"ListingInputFilterBean":{"searchItems": [], "listingStatus": "ACTIVE"}}'::JSONB),
  ('{"ListingInputFilterBean":{"searchItems": [{"name": "Dachshund", "type": "BREED"}], "listingStatus": "ACTIVE"}}'::JSONB),
  ('{"ListingInputFilterBean":{"searchItems": [{"name": "Lab", "type": "BREED"}, {"name": "Black Lab", "type": "CST"}], "listingStatus": "ACTIVE"}}'::JSONB)
)
SELECT search_item->>'name',count(search_item->>'name')
FROM
  log_activity la,
  jsonb_array_elements(la.data#>'{ListingInputFilterBean,searchItems}') as search_item
WHERE search_item->>'type' = 'BREED'
GROUP BY search_item;

结果:

   name    | count 
-----------+-------
 Lab       |     1
 Dachshund |     1
(2 rows)

在这里,您只需要遍历searchItems列表,并仅对符合条件的条目进行分组。步骤如下:

  1. 使用#>运算符获取jsonb searchItems数组,它将在指定路径获取JSON对象;
  2. 使用jsonb_array_elements()迭代从步骤1检索到的元素列表,该函数将JSON数组扩展为一组JSON值;
  3. count()名称,其中searchItems' type = BREED,您可以使用->>运算符获取实际文本值;
  4. 更新

    jsonb_to_recordset()看起来更短,但您需要明确定义search_item列'类型:

    SELECT search_item.name ,count(search_item.name)
    FROM
      log_activity la,
      jsonb_to_recordset(la.data#>'{ListingInputFilterBean,searchItems}') as search_item(name text,type text)
    WHERE search_item.type = 'BREED'
    GROUP BY search_item.name;