获取特定用户之间的消息子集

时间:2016-09-30 18:09:00

标签: sql postgresql

在我的应用中,用户

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,但什么是更有效的解决方案?

2 个答案:

答案 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