在我的应用中,用户
CREATE TABLE users (
id bigserial PRIMARY KEY,
username varchar(50) NOT NULL
);
可以发送消息
CREATE TABLE messages (
id bigserial PRIMARY KEY,
from_id bigint NOT NULL REFERENCES users ON DELETE RESTRICT,
body text NOT NULL CHECK (body <> ''),
created_at timestamp(0) NOT NULL DEFAULT LOCALTIMESTAMP(0)
);
对许多收件人
CREATE TABLE message_recipients (
message_id bigint NOT NULL REFERENCES messages ON DELETE CASCADE,
user_id bigint NOT NULL REFERENCES users ON DELETE RESTRICT,
PRIMARY KEY (message_id, user_id)
);
我如何SELECT
至少某个特定用户群之间的所有消息?
即如果总共有四个用户:{1,2,3,4},并且我指定的用户子集是{1,2,3},那么如何获取用户1,2之间的所有消息和3,包括用户1,2,3和4之间的所有那些,不包括仅1和2之间的任何消息。 2,或1&amp; 3或2&amp; 3?
注意:我提供了an answer below,但什么是更有效的解决方案?
答案 0 :(得分:0)
以下查询会获取包含特定用户子集的所有邮件。
WITH messages_with_recipients AS (
SELECT id, from_id, array_agg(r.user_id) AS to_ids, body, created_at
FROM messages AS m
JOIN message_recipients AS r
ON r.message_id = m.id
GROUP BY 1, 2, 4, 5
)
SELECT id, from_id, to_ids, body, created_at
FROM messages_with_recipients
WHERE array_append(to_ids, from_id) @> '{1, 2, 3}';
见SQL Fiddle&amp; PostgreSQL Documentation: Array Functions and Operators
答案 1 :(得分:0)
另一种方法是创建一个包含特定用户ID子集的表或临时表(例如,这可以在用户定义的函数中完成)。然后可以使用以下查询:
WITH messages_not_meeting_requirement AS
(SELECT message_id FROM
(SELECT m.id AS message_id,
subq.user_id
FROM subset s
CROSS JOIN messages m
LEFT JOIN
(SELECT r.message_id, r.user_id
FROM messages AS m
JOIN message_recipients AS r
ON r.message_id = m.id
UNION ALL
SELECT m.id AS message_id, m.from_id AS userid
FROM messages AS m) subq
ON subq.user_id = s.user_id
AND subq.message_id = m.id) subq2
WHERE subq2.user_id IS NULL)
SELECT *
FROM messages AS m
WHERE m.id NOT IN (SELECT message_id FROM messages_not_meeting_requirement);
在此处查看演示:http://rextester.com/PLQI90029