MySQL左外连接,排除属于用户的第二个表中的项目

时间:2012-06-15 21:13:08

标签: mysql join left-join

我的MySQL数据库中有两个表,一个是数据库中所有书籍的库,另一个是包含与用户库中书籍相对应的各个行。

例如:

图书馆表

 `id`        `title`...
=====        ===========
  1          Moby Dick
  2          Harry Potter

收集表

 `id`        `user`      `book`
=====        ======      =======
  1            1            2
  2            2            2
  3            1            1

我想要做的是运行一个查询,该查询将显示用户集合中的所有书籍。我可以运行此查询以显示不在任何用户的集合中的所有书籍:

SELECT * 
FROM  `library` 
LEFT OUTER JOIN  `collection` ON  `library`.`id` =  `collection`.`book` 
WHERE  `collection`.`book` IS NULL

据我所知,这很好用。在PHPMyAdmin中运行它将导致所有不在集合表中的书籍。

但是,如何将其限制为某个用户?例如,使用上面的虚拟数据,如果用户2运行查询,我希望书1结果,如果用户1运行查询,则不需要书籍。

添加AND user=[id]不起作用,而且我对JOIN语句的知识非常有限,我实际上并没有得到任何结论。

此外,返回的结果的ID(显示的查询,不执行我想要但功能正常)为0 - 如何确保返回的ID是library.id的ID?

2 个答案:

答案 0 :(得分:13)

您必须将LEFT JOIN选择范围缩小到只有特定用户拥有的图书,然后联接表中NULL的任何内容都是行(用户在他/她的收藏中没有的书籍:

SELECT
    a.id,
    a.title
FROM
    library a
LEFT JOIN
    (
        SELECT book
        FROM collection
        WHERE user = <userid>
    ) b ON a.id = b.book
WHERE 
    b.book IS NULL

另一种选择是:

SELECT
    a.id,
    a.title
FROM
    library a
WHERE 
    a.id NOT IN
    (
        SELECT book
        FROM collection
        WHERE user = <userid>
    )

然而,第一个解决方案更优化,因为MySQL将为每一行执行一次NOT IN子查询,而不是仅对整个查询执行一次。直观地说,你会期望MySQL一次执行子查询并将其用作列表,但MySQL不够聪明,无法区分相关子查询和非相关子查询。

如上所述here

  

“问题是,对于使用IN子查询的语句,   优化器将其重写为相关子查询。“

答案 1 :(得分:3)

这个怎么样?它只是我的头脑 - 我现在无法访问数据库进行测试。 (对不起)

SELECT 
   * 
FROM 
   library lib 
WHERE 
   lib.id NOT IN (
      SELECT 
         book 
      FROM 
         collection coll 
      WHERE 
         coll.user =[id]
   )
;