Postgres多对多:如何选择具有精确计数链接的记录

时间:2016-11-03 12:24:19

标签: postgresql many-to-many aggregate has-and-belongs-to-many

使用该模式(还有更多字段),我想知道选择完全聊天,其中clients.id例如344,345,它们恰好是两个。

但我发现他们与其他客户的所有聊天记录,不仅仅是他们两个。

Schema http://www.zimagez.com/miniature/107410861087108810861089-10871086-habtm0.png

大图http://www.zimagez.com/zimage/107410861087108810861089-10871086-habtm0.php

SELECT 
  chat_rooms.id, 
  chat_rooms.token
FROM 
  chat_rooms, 
  clients, 
  chat_rooms_clients
WHERE 
  chat_rooms_clients.chat_room_id = chat_rooms.id AND
  chat_rooms_clients.client_id = clients.id AND
  clients.id IN (344,354) AND 
  chat_rooms.meeting_id IS NULL
group by chat_rooms.id
having count(clients.id) = 2
ORDER BY
  chat_rooms.created_at DESC;

我的应用程序是用rails编写的。

1 个答案:

答案 0 :(得分:1)

使用提供的测试数据:

set search_path = testschema, pg_catalog;
select cr.id, array_agg(crc.client_id order by crc.client_id), cr.token
from
    chat_rooms_clients crc
    inner join
    chat_rooms cr on cr.id = crc.chat_room_id
where cr.meeting_id is null
group by 1
having array_agg(crc.client_id order by crc.client_id) = array[2467,2471]::int[]
order by cr.created_at desc;
 id  |  array_agg  |                token
-----+-------------+--------------------------------------
 234 | {2467,2471} | bd36db10-3a89-40fe-a3e3-524b4278b718

请注意,对于此查询,不必加入clients表。我认为在chat_rooms_clients表中创建主键是明智的:

create table chat_rooms_clients (
    chat_room_id integer not null,
    client_id integer not null,
    primary key (chat_room_id, client_id)
);

否则,为了安全起见,有必要在上述查询的distinct中添加array_agg

having array_agg(distinct crc.client_id order by crc.client_id) = ...

如果聊天室创建者必须是其中一个聊天参与者,则过滤它以提高性能:

where cr.meeting_id is null and cr.creator_id in (2467,2471)