严重编辑!
最初的问题是基于对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)
所以它似乎采用了一个1,2或2,3的GROUP_CONCAT字符串,并将其视为单个实体而不是表达式列表。有没有办法将分组列转换为IN()或= ANY()将其视为列表的表达式列表?
本质上,我试图在类似于数组或动态表达式列表的东西上迭代地进行IN()循环,该列表包含来自连接的所有数据行。
答案 0 :(得分:4)
考虑一下您的代码在逻辑上做了什么:
( 1 IN (tag.tag_id) ) AND ( 2 IN (tag.tag_id) )
相当于
( 1 = (tag.tag_id) ) AND (2 = (tag.tag_id) )
tag.tag_id
无法同时满足这两个条件,因此AND永远不会成立。
看起来您在问题中引用的OR版本是您真正想要的版本:
SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id
WHERE ( ( 1 IN (tag.tag_id) ) OR ( 2 IN (tag.tag_id) ) );
更恰当地使用IN子句,您可以将其写为:
SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id
WHERE tag.tag_id in (1,2);
最后要注意的是,因为你在WHERE子句(tag.tag_id
)中引用了LEFT JOINed表中的列,所以你真的强迫它表现得像INNER JOIN。要真正获得LEFT JOIN,您需要将标准移出WHERE并使其成为JOIN条件的一部分:
SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id
AND tag.tag_id in (1,2);
答案 1 :(得分:0)
WHERE ( ( 1 IN (tag.tag_id) ) AND ( 2 IN (tag.tag_id) ) );
由于tag.tag_id不能同时为1和2,因此永远不会返回任何结果。
此外,您使用1 IN (blah)
而非blah = 1