Mysql 有人能解释为什么这个左外连接是这样的吗?

Mysql 有人能解释为什么这个左外连接是这样的吗?,mysql,join,left-join,Mysql,Join,Left Join,我有两个表,item和item_popularity,需要查找作为输入提供的少数项目中不受欢迎的项目。我认为一个带有空检查的左外连接是正确的方法,但我一直有一些非常奇怪的行为。然后我对查询进行了一些修改,并使其正常工作,但我真的很想理解它为什么会这样 假设这些表具有以下值: item +----+----------+ | id | name | +----+----------+ | 1 | Item 1 | | 2 | Item 2 | | 3 | Item 3

我有两个表,item和item_popularity,需要查找作为输入提供的少数项目中不受欢迎的项目。我认为一个带有空检查的左外连接是正确的方法,但我一直有一些非常奇怪的行为。然后我对查询进行了一些修改,并使其正常工作,但我真的很想理解它为什么会这样

假设这些表具有以下值:

 item
+----+----------+
| id | name     |
+----+----------+
| 1  | Item 1   |
| 2  | Item 2   |
| 3  | Item 3   |
| 4  | Item 4   |
| 5  | Item 5   |
+----+----------+

item_popularity
+---------+-------------+----------+
| id_item | popularity  | id_store |
+---------+-------------+----------+
| 1       | 0.78        | 1        |
| 3       | 0.23        | 1        |
| 4       | 0.6765      | 1        |
+----+------------------+----------+
我最初的问题如下:

SELECT item.id, item.name, item_popularity.popularity FROM item
LEFT OUTER JOIN item_popularity
ON item.id = item_popularity.id_item
WHERE item.id IN (provided input)
AND id_store = (provided store)
AND item_popularity.id_item IS NULL
然而,这将不会返回任何项目,因为它只是加入了受欢迎的项目,如图所示。我在谷歌上搜索了一下,发现很多人都有同样的问题,到处都有人说要把WHERE子句的第一部分移到连接中,因为这样会导致左连接变成内部连接之类的

我这样做了,然后问题变成:

SELECT item.id, item.name, item_popularity.popularity FROM item
LEFT OUTER JOIN item_popularity
ON item.id = item_popularity.id_item
AND item.id IN (provided input)
AND id_store = (provided store)
WHERE item_popularity.id_item IS NULL
现在是奇怪的一点。假设我在寻找第2、3和5项。我知道只有3分受欢迎,所以我应该看到2分和5分的结果,对吗?嗯,有点。我在那里看到了2和5,但它也在结果中列出了1和4

好的,我获得正确结果的唯一方法是重复WHERE子句中的id过滤器,使查询看起来很难看,如图所示:


我不知道是否应该在WHERE中重复id_存储过滤器,我可能只是为了确定。有人能解释为什么会发生这种情况,以及有没有更好的方法来解决它吗?

第一个查询不起作用的原因不是因为左表中的条件,而是因为右表中有一个条件。完全删除fiddle中的WHERE子句,但选择要使用的所有字段,以便将其视为调试练习。因此,请使用:

SELECT item.id, item.name, item_popularity.popularity, id_store 
FROM item
LEFT OUTER JOIN item_popularity
ON item.id = item_popularity.id_item
执行此操作后,您将看到条件项_popularity.id_store=1将排除您看到被排除的记录

select item.id, item.name, item_popularity.popularity
from item 
left join item_popularity 
on item.id = item_popularity.id_item
where item_popularity.popularity is null
获取完整的item表,在它存在的地方添加popularity表,在不存在的地方添加null值。然后检查流行度有空值的位置。您还可以检查item_popularity.id_item,因为它在给定数据的相同行上有空值

select item.id, item.name, item_popularity.popularity
from item 
left join item_popularity 
on item.id = item_popularity.id_item
where item_popularity.popularity is null