You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LEFT JOIN查询排除collection_id=2却返回book_id=1,求问题原因

问题分析与解决方案

需求

获取所有未被加入到collection_id=2的书籍,但当前查询返回了属于该集合的book_id=1,不符合预期。

数据表结构与测试数据

CREATE TABLE db.books (
    id INT auto_increment not NULL,
    title varchar(100) NULL,
    category_id INT NULL,
    PRIMARY  key (id)
)

CREATE TABLE db.books_categories (
    id INT auto_increment not NULL,
    category varchar(100) NULL,
    PRIMARY  key (id)
)

CREATE TABLE db.collection (
    id INT auto_increment not NULL,
    title varchar(100) NULL,
    PRIMARY  key (id)
)

CREATE TABLE db.collections_has_books (
    id INT auto_increment not NULL,
    collection_id int not NULL,
    book_id int not NULL,
    PRIMARY  key (id)
)

ENGINE=InnoDB
DEFAULT CHARSET=latin1
COLLATE=latin1_swedish_ci;

INSERT INTO db.books (title,category_id) VALUES
     ('Harry Potter and the philosopher''s stone',2),
     ('The lord of the rings',2),
     ('Moby dick',3),
     ('Robinson Crusoe',3),
     ('The Time Machine',1),
     ('The Great Gatsby',4),
     ('The Treasure Island',3);

INSERT INTO db.books_categories (category) VALUES
     ('science_fiction'),
     ('fanstasy'),
     ('adventures'),
     ('other');

INSERT INTO db.collection (title) VALUES
     ('books for vacations'),
     ('books for teenagers'),
     ('first readings'),
     ('books about adventrues and other stuff');

INSERT INTO db.collections_has_books (collection_id, book_id) VALUES
     (1,1),
     (1,4),
     (1,5),
     (2,1),
     (2,2),
     (2,4),
     (3,4),
     (3,5),
     (4,4),
     (4,5),
     (4,6);

错误查询语句

SELECT distinct `b`.* FROM `books` `b` 
LEFT JOIN `books_categories` `c` 
ON c.id = b.category_id 
LEFT JOIN `collections_has_books` `chb` 
ON chb.book_id = b.id 
WHERE (chb.collection_id != 2)  

错误结果

idtitlecategory_id
1Harry Potter and the philosopher's stone2
4Robinson Crusoe3
5The Time Machine1
6The Great Gatsby4

错误原因

book_id=1同时存在于collection_id=1和2中,执行LEFT JOIN collections_has_books后会生成两条关于该书籍的记录:一条关联到collection_id=1,另一条关联到collection_id=2。

WHERE条件chb.collection_id !=2会过滤掉关联到collection_id=2的那条记录,但保留关联到collection_id=1的记录。最后DISTINCT去重时,book_id=1的记录依然会被保留,因为存在符合WHERE条件的关联记录。

另外,查询中LEFT JOIN books_categories但未使用该表的任何字段,对结果无影响,可以移除。

正确查询方案

方案一:使用NOT EXISTS(逻辑最直观)

直接判断当前书籍不存在于collection_id=2的关联记录中:

SELECT b.* 
FROM db.books b
WHERE NOT EXISTS (
    SELECT 1 
    FROM db.collections_has_books chb
    WHERE chb.book_id = b.id 
      AND chb.collection_id = 2
);

方案二:使用LEFT JOIN + IS NULL

将collection_id=2的条件放在JOIN的ON子句中,再筛选无关联记录的书籍:

SELECT DISTINCT b.*
FROM db.books b
LEFT JOIN db.collections_has_books chb 
  ON chb.book_id = b.id 
  AND chb.collection_id = 2
WHERE chb.id IS NULL;

方案三:使用GROUP BY + HAVING

统计书籍关联到collection_id=2的次数,筛选次数为0的书籍:

SELECT b.*
FROM db.books b
LEFT JOIN db.collections_has_books chb ON chb.book_id = b.id
GROUP BY b.id
HAVING SUM(CASE WHEN chb.collection_id = 2 THEN 1 ELSE 0 END) = 0;

正确结果

idtitlecategory_id
3Moby dick3
5The Time Machine1
6The Great Gatsby4
7The Treasure Island3

内容的提问来源于stack exchange,提问作者paul mart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:00:42