如何在 Postgres 中对 json 数据进行计算
How to do calculations on json data in Postgres
我将 AdWords 报告数据存储在 Postgres 中。每个报告都存储在一个名为 table 的 Reports 中,其中有一个名为 'data' 的 jsonb 列。每个报告都有 json 存储在其 'data' 字段中,看起来像这样:
[
{
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 中做的事情是可能的吗?我是否需要从该数组中创建一个临时 table 并对其进行计算?或者我可以使用存储过程吗?
我正在使用 Postgresql 9.4
编辑
我不只是使用常规的、规范化的 table 的原因是,这只是如何构建报告数据的一个示例。在我的项目中,报告必须允许任意键,因为它们是由用户使用他们喜欢的任何列上传 CSV 来填充的。它基本上只是一种绕过任意多个用户创建的 tables 的方法。
你可以使用 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
.
What I want to do is query off these data hashes and sum up the conversions
最快的方法应该是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
);
临时 table 是一种临时注册行类型的方法。此相关答案中的更多解释:
由于缺乏信息,假设 table report
与 report_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;
即使 data
为 NULL 或空或者 JSON 数组为空,LEFT JOIN
确保您得到结果。
对于基础 table 中 单行 的总和,速度更快:
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
通常你会把它实现为普通的、规范化的 table。我在这里看不到 JSON 的好处(除了您的应用程序似乎需要它,就像您添加的那样)。
我将 AdWords 报告数据存储在 Postgres 中。每个报告都存储在一个名为 table 的 Reports 中,其中有一个名为 'data' 的 jsonb 列。每个报告都有 json 存储在其 'data' 字段中,看起来像这样:
[
{
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 中做的事情是可能的吗?我是否需要从该数组中创建一个临时 table 并对其进行计算?或者我可以使用存储过程吗?
我正在使用 Postgresql 9.4
编辑 我不只是使用常规的、规范化的 table 的原因是,这只是如何构建报告数据的一个示例。在我的项目中,报告必须允许任意键,因为它们是由用户使用他们喜欢的任何列上传 CSV 来填充的。它基本上只是一种绕过任意多个用户创建的 tables 的方法。
你可以使用 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
.
What I want to do is query off these data hashes and sum up the conversions
最快的方法应该是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
);
临时 table 是一种临时注册行类型的方法。此相关答案中的更多解释:
由于缺乏信息,假设 table report
与 report_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;
即使 data
为 NULL 或空或者 JSON 数组为空,LEFT JOIN
确保您得到结果。
对于基础 table 中 单行 的总和,速度更快:
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
通常你会把它实现为普通的、规范化的 table。我在这里看不到 JSON 的好处(除了您的应用程序似乎需要它,就像您添加的那样)。