我有下表:
CREATE TABLE mytable ( id serial PRIMARY KEY , employee text UNIQUE NOT NULL , data jsonb );
带有以下数据:
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"}')
请注意,除了“ sales_tv”和“ sales_radio”之外,还有其他键。对于下面的查询,我只需要关注“ sales_tv”和“ sales_radio”。
我需要查找Jim在2012年的所有销售额。任何以“ sales_”开头的内容,然后将其放在一个对象中(只需要所售产品的价值和价值)即可。例如:
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'
但我似乎甚至无法获得吉姆的数据。相反,我得到:
employee | key | value -------- |------ | ----- Jim | sales_tv | [{"yr": "2010", "loc": "us", "value": 4}, {"yr": "2011", "loc": "europe", "value": 18}, {"yr": "2012", "loc": "asia", "value": 28}] Jim | sales_tv | [{"yr": "2010", "loc": "us", "value": 10}, {"yr": "2011", "loc": "europe", "value": 5}, {"yr": "2012", "loc": "asia", "value": 40}] Jim | sales_radio | [{"yr": "2010", "loc": "us", "value": 11}, {"yr": "2011", "loc": "china", "value": 8}, {"yr": "2012", "loc": "us", "value": 76}]
您将第一次连接的结果视为JSON,而不是文本字符串,因此请使用 jsonb_each() 代替jsonb_each_text():
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。 结果:
GROUP BY 1
GROUP BY t.employee
employee | sales ---------+-------- Jim | '{ "sales_tv" : 40, "sales_radio" : 76 }'
我还理清和简化了您的查询。
json_object_agg() 在将名称/值对作为JSON对象进行聚合时发挥了作用。jsonb如果需要,可以选择强制转换为-或jsonb_object_agg()在Postgres 9.5或更高版本中使用。
json_object_agg()
jsonb
jsonb_object_agg()
使用显式JOIN语法将条件附加在最明显的位置。没有显式语法 的情况相同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;