我有下表:
CREATE TABLE tbl (tbl_id int, messages jsonb);
CREATE INDEX index_tbl ON tbl USING gin (messages);
将JSON消息作为数组:
[{"user_id":1,"created_at":"2016-12-20","content":"Suspendisse accumsan tortor quis turpis. Sed ante."},
{"user_id":2,"created_at":"2016-12-20","content":"Morbi sem mauris tibulum sagittis sapien."},
{"user_id":1,"created_at":"2016-10-21","content":"In blandit ultrices enim. Phasellus id sapien in sapien iaculis congue."},
{"user_id":3,"created_at":"2016-11-20","content":"Quisque ut erat. Curabitur gravida nisi at nibh. In hac habitasse platea dictumst."},
{"user_id":4,"created_at":"2016-12-21","content":"Nunc rhoncus dui vel sem. Sed sagittis. ectus. Pellentesque at nulla. Suspendisse potenti. Cras in purus eu magna vulputate luctus."},
{"user_id":6,"created_at":"2016-12-21","content":"Praesent id massa id nisl venenatis lacinia. iaculis congue."}]
如何在一个月内选择用户所在的邮件? 例如,12月份的用户只返回用户2,4和6的消息,因为用户1也在11月份。
答案 0 :(得分:2)
这将返回所有..
用户仅在一个月内的消息
WITH msg AS (
SELECT tbl_id
,(msg->>'user_id')::int AS user_id
, date_trunc('month', (msg->>'created_at')::timestamp)::date AS created_month
, msg->>'content' AS content
FROM tbl t, jsonb_array_elements(t.messages) msg
)
SELECT m.*
FROM (
SELECT user_id
FROM msg
GROUP BY 1
HAVING count(DISTINCT created_month) = 1
) u
JOIN msg m USING (user_id);
使用jsonb_array_elements()
解析JSON数组。
提取相关键的值。只有日期的月份相关,请使用date_trunc()
并将结果投回date
。
在步骤 1。和 2生成的CTE msg
上运行实际查询。识别仅在一个月内发布的用户 - 跨整个表格,而不仅仅是一排。你没有澄清,我选择了这种解释。
自我加入同一个CTE msg
以返回标识用户的所有消息。
GIN索引无济于事,因为您需要以任何方式检查每个数组元素。
将消息存储在规范化的表格中,对于您的查询来说更简单,更快捷:
message (user_id int, created_at date, content text)