【发布时间】:2011-01-10 16:41:04
【问题描述】:
大量编辑!
最初的问题是基于对 IN() 如何处理来自连接的结果集中的列的误解。我认为 IN( some_join.some_column ) 会将结果列视为列表并在每一行中循环。事实证明它只查看第一行。
那么,修改后的问题是:MySQL 中是否有任何东西可以遍历来自 WHERE 子句的连接的一列结果?
这是我正在使用的超级简化代码,从复杂的 crm 搜索功能中剥离出来。左连接和一般思想是该查询的遗物。因此,对于这个查询,它必须是一个排他性搜索 - 查找具有所有指定标签的人,而不仅仅是任何标签。
首先是数据库
表 1:人
+----+------+
| id | name |
+----+------+
| 1 | Bob |
| 2 | Jill |
+----+------+
表 2:标签
+-----------+--------+
| person_id | tag_id |
+-----------+--------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 2 | 3 |
+-----------+--------+
漂亮而简单。所以,很自然:
SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id GROUP BY name;
+------+--------------------------+
| name | GROUP_CONCAT(tag.tag_id) |
+------+--------------------------+
| Bob | 1,2 |
| Jill | 2,3 |
+------+--------------------------+
到目前为止一切顺利。所以我正在寻找的是在第一种情况下只能找到 Bob 而在第二种情况下只能找到 Jill 的东西 - 不使用 HAVING COUNT(DISTINCT ...) 因为这在更广泛的查询中不起作用(有一个单独的标签继承缓存和大量其他东西)。
这是我最初的示例查询 - 基于 IN() 将一次循环遍历所有行的错误想法。
SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id
WHERE ( ( 1 IN (tag.tag_id) ) AND ( 2 IN (tag.tag_id) ) );
Empty set (0.00 sec)
SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id
WHERE ( ( 2 IN (tag.tag_id) ) AND ( 3 IN (tag.tag_id) ) );
Empty set (0.00 sec)
这是我最近一次失败的尝试,试图说明我的目标......
SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id
GROUP BY person.id HAVING ( ( 1 IN (GROUP_CONCAT(tag.tag_id) ) ) ) AND ( 2 IN (GROUP_CONCAT(tag.tag_id)) );
Empty set (0.00 sec)
因此,它似乎采用 GROUP_CONCAT 字符串,1,2 或 2,3,并将其视为单个实体而不是表达式列表。有什么方法可以将分组列转换为 IN () 或 =ANY() 将视为列表的表达式列表?
基本上,我试图让 IN() 在类似于数组或动态表达式列表的东西上迭代循环,其中包含来自连接的所有数据行。
【问题讨论】:
-
所以再进行一些测试,如果我使用 = 而不是 IN,这些结果似乎是相同的。所以,也许,MySQL 优化器正在将我的 'IN' 转换为 '=',看到这给出了“P = X AND P = Y”,因此返回一个几乎不接触数据库的空结果集 - 因此超级快速响应时间
-
超快的响应时间可能是由于 WHERE 条件永远不会为真,因此不需要读取任何行。见乔的回答。