连接不存在查询的表

时间:2012-06-26 15:43:11

标签: mysql left-join not-exists

  

可能重复:
  Mysql: Perform of NOT EXISTS. Is it possible to improve permofance?

有没有更好/最佳的方式来做到这一点。我应该使用exists代替join吗?还是两个单独的查询?那些临时表格,正如我正在阅读的那些但不确定。

从一个组中获取成员的电子邮件。检查他们还没有收到任何物品。

SELECT m.email,g.id 
FROM group g 
  LEFT JOIN  members m 
    ON  g.mid = m.id 
    AND g.gid='1' 
WHERE NOT EXISTS 
      ( SELECT id 
        FROM items AS i 
        WHERE i.mid=m.id 
        AND i.item_id='5'
      ) 

2 个答案:

答案 0 :(得分:4)

这是与JOIN相同的东西:

SELECT m.email, g.id
From members m
JOIN group g ON g.mid = m.id AND g.gid = '1' 
LEFT JOIN items i ON i.mid = m.id AND i.item_id = '5'
WHERE i.id IS NULL

使用以下复合索引:

group (mid, gid)
items (mid, item_id)

我改变了成员和组的LEFT JOIN,因为看起来你正在返回成员,而不是组,并且我将LEFT JOIN更改为INNER JOIN,因为你只需要来自该组的成员。

我认为这个可能会更好看:

SELECT m.email, g.id
From members m
JOIN group g ON g.mid = m.id
LEFT JOIN items i ON i.mid = m.id AND i.item_id = 5
WHERE g.gid = 1
  AND i.id IS NULL

您可能想知道我们是否也可以将i.item_id = 5部分移动到WHERE子句中。您不能,因为没有i.id IS NULLi.item_id = 5的行。您必须先进行连接,然后消除WHERE子句中的NULL行。

答案 1 :(得分:1)

我不相信临时表是必要的。如果我们无法获得可接受的表现,我们真的只会走这条路。

从您的查询中,我们收集您的架构如下:

group (id INT PK, gid INT, mid INT)
items (id INT PK, item_id INT, mid INT)
members (id INT PK, email VARCHAR)

看起来您的group表实际上是一个“成员资格”表,它解决/实现了一个组与一个人之间的多对多关系。 (也就是说,一个人可以是零个,一个或多个组的成员;一个组可以有零个或多个人作为成员。)

您在groupmembers之间使用LEFT JOIN。当没有匹配的成员时,这将为group返回一行(返回group.id),member.email为NULL(这可能是你想要的)。但是,如果您只想返回电子邮件地址,则可以将其更改为INNER JOIN。

可以使用OUTER JOIN替换NOT EXISTS谓词,并测试从JOINED表返回的NULL值。如果group.gid和/或items.item_id列是数值数据类型,则可以从谓词中的整数文字中删除引号。

这是一个替代方法,它将返回一个等效的结果集,并且可能表现更好:

SELECT m.email
     , g.id 
  FROM members m
  JOIN group g ON g.mid = m.id AND g.gid = 1
  LEFT
  JOIN items i ON i.mid = m.id AND i.item_id = 5
 WHERE i.id IS NULL

附录:

TEST CASE(在对所选答案的评论中提供)演示了在items.item_id = 5子句和ON子句中具有谓词{{​​1}}的查询之间的结果集的差异。 (将此谓词移动到WHERE子句会使用反连接。)

WHERE