2016-09-30 68 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