MySQL:遇到麻烦的事情'确切的'而不是'至少'

时间:2016-01-21 21:24:52

标签: mysql

我有一个表格,其中包含参与对话的用户关系,如下所示:

CREATE TABLE `so` (
  `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `user_id` int(11) NOT NULL,
  `conversation_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `so`
  ADD UNIQUE KEY `uc` (`user_id`,`conversation_id`) USING BTREE;

INSERT INTO `so` (`id`, `user_id`, `conversation_id`) VALUES
(1, 1, 1),
(3, 1, 2),
(2, 2, 1),
(4, 2, 2),
(5, 3, 2);

根据样本数据,用户1和2的ID为1,用户为1,2,3,ID为2的会话。

我需要为用户ID列表获取唯一conversation_id

我目前的查询是:

SELECT conversation_id, COUNT(user_id) as usersCount
FROM so
WHERE user_id IN (1,2)
GROUP BY conversation_id
HAVING usersCount = 2
ORDER BY NULL

但它为两个对话返回2行,我希望对话框的行为1。

如何选择完全属于用户1和2的行,而不是1,2,3?感谢。

更新: 出于性能原因,我无法在连接上使用子查询,因为查询中的用户列表最多可能有30个ID,而我恐怕30个子查询不是这种情况。

3 个答案:

答案 0 :(得分:3)

您可以使用group_concat

select conversation_id
from so
group by conversation_id
having group_concat(user_id order by user_id) = '1,2';

要避免完整索引扫描,可以将原始查询放在子查询中:

SELECT a.conversation_id
FROM (
    SELECT conversation_id
    FROM so
    WHERE user_id IN (1,2)
    GROUP BY conversation_id
    HAVING COUNT(conversation_id) = 2) a
JOIN so b ON a.conversation_id = b.conversation_id
GROUP BY a.conversation_id
HAVING COUNT(a.conversation_id) = 2;

答案 1 :(得分:2)

不是检查user_id子句中的WHERE,而是将满足该条件的行数与每个会话的总行数进行比较。

SELECT conversation_id, COUNT(*) AS allCount, SUM(user_id IN (1, 2)) AS userCount
FROM so
GROUP BY conversation_id
HAVING allCount = 2 AND allCount = userCount

答案 2 :(得分:1)

这个答案是已经给出的替代方案,并且通过不使用子选择将提供更高的效率。

HAVING COUNT(user_id IN ('1','2') OR NULL) > 0指定您希望与用户ID 1和2进行对话。

COUNT(user_id) = 2表示对话中只能有2个用户。

如果您没有在练习中使用它,您甚至可以从结果集中删除COUNT(user_id) as usersCount

SELECT conversation_id, COUNT(user_id) as usersCount
FROM so
GROUP BY conversation_id
HAVING COUNT(user_id IN ('1','2') OR NULL) > 0 AND
COUNT(user_id) = 2;

为避免完整索引扫描,您必须使用where子句,因为@Fabricator已在其答案中显示。将条件应用于行组时,必须先将它们分组,然后执行聚合和条件,where子句仅将条件应用于单行。你的桌子有多大兴趣?

相关问题