10

我的 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 中运行它会导致所有不在收藏表中的书籍。

但是,如何将其限制为特定用户?例如,对于上面的虚拟数据,如果用户运行查询,我希望得到第 1 本书,如果用户2运行查询,我希望没有书籍1

仅添加 aAND user=[id]是行不通的,而且由于我对JOIN语句的了解极为有限,我真的一无所获。

此外,返回的结果的 ID(显示的查询,它不做我想要的但确实起作用)是 0 - 我如何确保返回的 ID 是library.id

4

2 回答 2

15

您必须将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 不够聪明,无法区分相关子查询和非相关子查询。

如此处所述:

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

于 2012-06-15T21:20:39.840 回答
4

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

SELECT 
   * 
FROM 
   library lib 
WHERE 
   lib.id NOT IN (
      SELECT 
         book 
      FROM 
         collection coll 
      WHERE 
         coll.user =[id]
   )
;
于 2012-06-15T21:30:37.577 回答