此查询有效:
person.posts.includes(:categories).
references(:categories).where(categories: { id: 20 })
但是在NOT条件下:
person.posts.includes(:categories).
references(:categories).where.not(categories: { id: 20 })
第二个查询完成且没有错误 - 但没有对结果进行过滤 - 因此它返回所有帖子。
MySQL:
SELECT COUNT(DISTINCT `posts`.`id`) FROM `posts`
LEFT OUTER JOIN `category_manifests` ON `category_manifests`.`post_id` = `posts`.`id`
LEFT OUTER JOIN `categories` ON `categories`.`id` = `category_manifests`.`category_id`
WHERE `posts`.`person_id` = 14 AND (`categories`.`id` != 20)
我在Activerecord文档中没有找到任何建议,这是不可能的 - 我在这里遗漏了一些基本的东西吗?
答案 0 :(得分:2)
可能是每个帖子都出现在该联接表某处中,其中联接表中的行具有categories.id<> 20.加入表最终看起来像这样:
struct
假设您想要与条形图5连接的foos。
如果你说,对于这个示例表,给我不同的foos.id,其中bars.id = 5你会得到这些行:
foos.id foos.name bars.id bars.name
1 qux 5 bux
2 qaz 5 bux
1 qux 6 bax
2 qaz 6 bax
3 qiz 5 bux
给你foos.ids 1,2,3。
如果你说“给我不同的foos.id where bars.id<> 5”,你可能会直觉地认为你得到的全套foo ID减去你从前一个查询得到的那些,即[]。你认为你在问“给我没有加入5号栏的foos”。但你得到的是这些行:
1 qux 5 bux
2 qaz 5 bux
3 qiz 5 bux
因为这些是bars.id<>的行这些行中的foos.ids是[1,2]。这似乎与你的情况类似。
换句话说,您希望获得“未加入第20类的帖子”,但您实际要求的是“加入到没有ID 20的类别的帖子”。从逻辑上讲,这略有不同。
答案 1 :(得分:1)
同意Max。我会像这样构建这种情况:
.where("NOT EXISTS (
SELECT * FROM category_manifests
WHERE post_id = posts.id AND category_id = ?)",
excluded_category.id)
相反,只是因为这种方式你不能在连接表数学中纠缠不清。