Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL:计数“精确”而不是“至少”的问题_Mysql - Fatal编程技术网

MySQL:计数“精确”而不是“至少”的问题

MySQL:计数“精确”而不是“至少”的问题,mysql,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

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

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列表获取唯一的对话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行,我希望对话id为1的行

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

更新: 出于性能原因,我不能在连接上使用子查询,因为查询中的用户列表可能最多有30个ID,而我担心30个子查询不是这样

您可以使用group_concat

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

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;
您可以使用group_concat

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

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;

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

如果COUNTuser_id位于“1”、“2”或NULL>0,则指定您希望与用户id 1和2进行对话

COUNTuser_id=2表示对话中只能有2个用户

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
如果您没有将COUNTuser_id用作练习的一部分,甚至可以将其从结果集中删除为UserScont

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子句,正如@mummercor在其答案中所示。当您将条件应用于行组时,它必须首先对行组进行分组,然后执行聚合和条件,where子句仅将条件应用于单行。您感兴趣的表格有多大?

此答案是已经给出的答案的另一种选择,通过不使用子选项,将提供更好的效率

如果COUNTuser_id位于“1”、“2”或NULL>0,则指定您希望与用户id 1和2进行对话

COUNTuser_id=2表示对话中只能有2个用户

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
如果您没有将COUNTuser_id用作练习的一部分,甚至可以将其从结果集中删除为UserScont

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子句,正如@mummercor在其答案中所示。当您将条件应用于行组时,它必须首先对行组进行分组,然后执行聚合和条件,where子句仅将条件应用于单行。您的表有多大?与其在WHERE子句中检查用户id,不如将满足该条件的行数与每个对话的总行数进行比较

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
不要在WHERE子句中检查user_id,而是将满足该条件的行数与每个对话的总行数进行比较

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


谢谢,这个查询有效。有没有办法避免完全索引扫描,因为表格会相对较大。你能解释一下group_concat的实际功能吗?我看到它得到了正确的结果集。我经常在类似的情况下使用类似于我答案中的查询,了解这一点可能会有所帮助。@Kanstantsin,请参阅更新的答案@AdamCopley,组_concat的行为类似于中的内爆“,”,$itemsphp@Fabricator,很遗憾,我在第二个查询中使用了无效的组函数。@Kanstantsin,很抱歉我没有测试它。现在应该可以了谢谢,这个查询可以了。有没有办法避免完全索引扫描,因为表格会相对较大。你能解释一下group_concat的实际功能吗?我看到它得到了正确的结果集。我经常在类似的情况下使用类似于我答案中的查询,了解这一点可能会有所帮助。@Kanstantsin,请参阅更新的答案@AdamCopley,组_concat的行为类似于中的内爆“,”,$itemsphp@Fabricator,很遗憾,我在第二个查询中使用了无效的组函数。@Kanstantsin,很抱歉我没有测试它。现在应该可以用了。这个也可以,谢谢。您能建议如何避免完全索引扫描吗?表中可能有数百万行。这些是表中唯一使用和筛选的列,还是为了便于解释而对其进行了精简?如果只是3,那么简单地在用户id、对话id上建立一个索引将为您提供最佳结果。我有一个类似的情况,我以类似的方式过滤产品数据,最多有300万行,这是我正在努力优化的,但是也有一些连接对这种情况没有帮助。在一个没有连接的表上,像这里回答的任何3个查询都可以做到。这一个也可以,谢谢。您能建议如何避免完全索引扫描吗?表中可能有数百万行。这些是表中唯一使用和筛选的列,还是为了便于解释而对其进行了精简?如果只是3,那么简单地在用户id、对话id上建立一个索引就可以得到最好的结果
类似的方式有多达3米的行,我正在努力优化,但是也有一些连接对情况没有帮助。在一个没有连接的表上,像这里回答的任何3个查询都可以做到这一点。在用大量数据填充一个表之后,您的查询似乎是唯一完成这项工作的查询。您认为,有什么方法可以避免完全索引扫描并提高查询的性能?在用大量数据填充表之后,您的查询似乎是唯一完成此任务的查询。您认为有什么方法可以避免完全索引扫描并提高查询性能?