2016-09-30 37 views
0

在我的应用程序之间的消息的一个子集,用户获取特定用户

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或1 & 3或2 & 3之间的任何消息。

注:我提供了an answer below,但什么是更有效的解决方案?

+0

你会考虑指定以不同的方式的目标用户子集,例如通过填充用于此目的的'user_id'表格? –

回答

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 & PostgreSQL Documentation: Array Functions and Operators

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