【问题标题】:How to do calculations on json data in Postgres如何在 Postgres 中对 json 数据进行计算
【发布时间】:2015-03-19 13:03:54
【问题描述】:

我将 AdWords 报告数据存储在 Postgres 中。每个报告都存储在一个名为 Reports 的表中,该表有一个名为“data”的 jsonb 列。每个报告都有 json 存储在其“数据”字段中,如下所示:

[
  {
    match_type: "exact",
    search_query: "gm hubcaps",
    conversions: 2,
    cost: 1.24
  },
  {
    match_type: "broad",
    search_query: "gm auto parts",
    conversions: 34,
    cost: 21.33
  },
  {
    match_type: "phrase",
    search_query: "silverdo headlights",
    conversions: 63,
    cost: 244.05
  }
]

我想要做的是查询这些数据哈希并总结给定报告的总转化次数。我查看了 Postgresql 文档,看起来你只能对哈希进行计算,而不是像这样的哈希数组。我正在尝试在 postgres 中做些什么?我是否需要从这个数组中创建一个临时表并对其进行计算?或者我可以使用存储过程吗?

我使用的是 Postgresql 9.4

编辑 我不只是使用常规的规范化表格的原因是,这只是报告数据结构的一个示例。在我的项目中,报告必须允许任意键,因为它们是由用户上传 CSV 和他们喜欢的任何列来填充的。它基本上只是一种解决任意数量的用户创建表的方法。

【问题讨论】:

  • 也许您应该将其设为永久表,因为这种结构完全适合关系模型,并且将其保存在 JSON 中意味着每个查询都将变得更加复杂且效率更低。
  • 表定义(psql 中的\d tbl)和您的 Postgres 版本对于这个问题是必不可少的。另外:每个报告或整体的总和约定?

标签: sql json postgresql jsonb


【解决方案1】:

我想要做的是查询这些数据哈希并总结转换

最快的方法应该是jsonb_populate_recordset()。但是你需要一个注册的行类型。

CREATE TEMP TABLE report_data (
--   match_type text    -- commented out, because we only need ..
-- , search_query text  -- .. conversions for this query
     conversions int
-- , cost numeric
);

临时表是临时注册行类型的一种方法。此相关答案中的更多解释:

假设一个表 reportreport_id 作为缺少信息的 PK。

SELECT r.report_id, sum(d.conversions) AS sum_conversions
FROM   report r
LEFT   JOIN LATERAL jsonb_populate_recordset(null::report_data, r.data) d ON true
-- WHERE  r.report_id = 12345  -- only for given report?
GROUP  BY 1;

LEFT JOIN 可确保您获得结果,即使 data 为 NULL 或空或 JSON 数组为空。

对于基础表中单行的总和,这更快:

SELECT d.sum_conversions
FROM   report r
LEFT   JOIN LATERAL (
   SELECT sum(conversions) AS sum_conversions
   FROM   jsonb_populate_recordset(null::report_data, r.data)
   ) d ON true
WHERE  r.report_id = 12345;  -- enter report_id here

jsonb_array_elements() 的替代品(不需要注册的行类型):

SELECT d.sum_conversions
FROM   report r
LEFT   JOIN LATERAL (
   SELECT sum((value->>'conversions')::int) AS sum_conversions
   FROM   jsonb_array_elements(r.data)
   ) d ON true
WHERE  r.report_id = 12345;  -- enter report_id here

通常,您会将其实现为普通的规范化表。我在这里看不到 JSON 的好处(除了您的应用程序似乎需要它,就像您添加的那样)。

【讨论】:

  • 我听到你在规范化。我采用这种方法的原因是因为该项目要求用户可以上传任何 csv 文档,无论其结构如何以及其中包含哪些列。我只是以这个 AdWords 报告为例。
  • 另外,感谢您指出缺乏细节。我将编辑问题。
【解决方案2】:

你可以使用unnest:

select sum(conv) from
(select d->'conversion' as conv from
(select unnest(data) as d from <your table>) all_data
) all_conv

免责声明:我没有 Pg 9.2,所以我无法自己测试。

编辑:这是假设您提到的数组是 Postgresql 数组,即您的 data 列的数据类型是 character varying[]。如果您的意思是 data 是一个 json 数组,您应该可以使用 json_array_elements 而不是 unnest

【讨论】:

  • unnest() 只能应用于 Postgres 数组。不是 jsonjsonb 类型内的 JSON 数组。
  • 数组,其实就是jsonb类型。我会试试 json_array_elements。
猜你喜欢
  • 2015-04-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-31
  • 1970-01-01
  • 2021-10-03
  • 2019-10-31
  • 1970-01-01
  • 2017-12-02
相关资源
最近更新 更多