我有下表:
rpart.control
使用以下数据:
CREATE TABLE mytable (
id serial PRIMARY KEY
, employee text UNIQUE NOT NULL
, data jsonb
);
请注意除了“sales_tv”和“sales_radio”之外还有其他键。对于下面的查询,我只需要关注“sales_tv”和“sales_radio”。
我需要找到2012年吉姆的所有销售。任何以“sales_”开头然后把它放在一个对象中的东西(只需要产品销售的是什么和价值)。 e.g:
INSERT INTO mytable (employee, data)
VALUES
('Jim', '{"sales_tv": [{"value": 10, "yr": "2010", "loc": "us"}, {"value": 5, "yr": "2011", "loc": "europe"}, {"value": 40, "yr": "2012", "loc": "asia"}], "sales_radio": [{"value": 11, "yr": "2010", "loc": "us"}, {"value": 8, "yr": "2011", "loc": "china"}, {"value": 76, "yr": "2012", "loc": "us"}], "another_key": "another value"}'),
('Rob', '{"sales_radio": [{"value": 7, "yr": "2014", "loc": "japan"}, {"value": 3, "yr": "2009", "loc": "us"}, {"value": 37, "yr": "2011", "loc": "us"}], "sales_tv": [{"value": 4, "yr": "2010", "loc": "us"}, {"value": 18, "yr": "2011", "loc": "europe"}, {"value": 28, "yr": "2012", "loc": "asia"}], "another_key": "another value"}')
我有:
employee | sales_
Jim | {"sales_tv": 40, "sales_radio": 76}
但我似乎无法得到吉姆的数据。相反,我得到:
SELECT * FROM mytable,
(SELECT l.key, l.value FROM mytable, lateral jsonb_each_text(data) AS l
WHERE key LIKE 'sales_%') AS a,
jsonb_to_recordset(a.value::jsonb) AS d(yr text, value float)
WHERE mytable.employee = 'Jim'
AND d.yr = '2012'
答案 0 :(得分:2)
您将第一次加入的结果视为JSON,而不是文本字符串,因此请使用jsonb_each()
代替jsonb_each_text()
:
SELECT t.employee, json_object_agg(a.k, d.value) AS sales
FROM mytable t
JOIN LATERAL jsonb_each(t.data) a(k,v) ON a.k LIKE 'sales_%'
JOIN LATERAL jsonb_to_recordset(a.v) d(yr text, value float) ON d.yr = '2012'
WHERE t.employee = 'Jim' -- works because employee is unique
GROUP BY 1;
GROUP BY 1
是GROUP BY t.employee
的简写
结果:
employee | sales
---------+--------
Jim | '{ "sales_tv" : 40, "sales_radio" : 76 }'
我也解开并简化了您的查询。
json_object_agg()
有助于将名称/值对聚合为JSON对象。如果需要,可以选择转换为jsonb
- 或者在Postgres 9.5或更高版本中使用jsonb_object_agg()
。
使用明确的JOIN
语法将条件附加到最明显的位置
相同的,没有明确的JOIN
语法:
SELECT t.employee, json_object_agg(a.k, d.value) AS sales
FROM mytable t
, jsonb_each(t.data) a(k,v)
, jsonb_to_recordset(a.v) d(yr text, value float)
WHERE t.employee = 'Jim'
AND a.k LIKE 'sales_%'
AND d.yr = '2012'
GROUP BY 1;
答案 1 :(得分:0)
您的第一个查询可以像这样解决(从臀部拍摄,此处无法访问PG 9.4):
SELECT employee, json_object_agg(key, sales)::jsonb AS sales_
FROM (
SELECT t.employee, j.key, sum((e->>'value')::int) AS sales
FROM mytable t,
jsonb_each(t.data) j,
jsonb_array_elements(j.value) e
WHERE t.employee = 'Jim'
AND j.key like 'sales_%'
AND e->>'yr' = '2012'
GROUP BY t.employee, j.key) sub
GROUP BY employee;
这里的诀窍是你使用LATERAL
加入"剥离" jsonb
对象的外层,以获取更深层次的数据。此查询假设Jim可能在多个位置进行销售。
(处理您的查询2)