【问题标题】:PostgreSQL or SQL in general: LEFT OUTER JOIN and WHERE condition behave unexpectedly (for me?)一般的 PostgreSQL 或 SQL:LEFT OUTER JOIN 和 WHERE 条件的行为异常(对我来说?)
【发布时间】:2016-01-28 00:52:06
【问题描述】:

假设我有两个表,它们可能有关系,也可能没有关系。例如,书籍和标签。所以,假设我要选择没有标签“Sci-Fi”的书籍,我会这样写:

SELECT
  *
FROM
  books
LEFT OUTER JOIN
  tags ON books.id = tags.taggable_id
WHERE
  tags.name NOT IN ('Sci-Fi')

我没想到这也会排除完全没有标签的书籍。 我试过这个:

WHERE
  tags.name IN (NULL, 'Novel'...)

最后得到了这个,我很确定这不是最好的方法:

WHERE
  tags.name NOT IN ('Sci-Fi') OR tags.id IS NULL

问题是为什么,还有其他方法吗?

附:不要问为什么以这种方式创建标签,这只是为了举例,这是我设法从自己身上挤出的最好的比喻:)

【问题讨论】:

  • 只是备注:这不会选择“没有标签'Sci-Fi'的书”,而是选择所有标签除'Sci-Fi'以外的所有书。要执行前者,您将使用 NOT EXISTS 而不是加入表格。
  • 说'我想选择没有标签“科幻”的书'我的意思是我对没有标签的书也很感兴趣。两个答案建议将条件 tags.name NOT IN ('Sci-Fi') 移动到 JOIN 子句,但据我所知,这只会使标签字段为空,但仍会选择具有 Sci-Fi 标签的书籍。
  • 不,我的意思是:您不是在选择书籍,而是在选择书籍标签组合
  • 哦,好吧,那么:)我会考虑这个,但我需要'join-way',因为我正在使用rails并寻找一种方法来使用AR而不是纯sql来做到这一点: )
  • 您想要没有特定标签的书籍,还是想要没有任何更大标签的书籍?因为仅针对列表中的一个值执行此操作的最清晰方法不涉及NOT IN。 (看起来您可能使用 NOT IN 只是因为您认为它在 <> 不起作用时有效。)您希望结果中的哪些列?

标签: sql postgresql outer-join


【解决方案1】:

where 子句中的所有条件都会过滤结果数据。所以将Sci-Fi 条件放在join 子句上

SELECT *
FROM books
LEFT OUTER JOIN tags ON books.id = tags.taggable_id
                    AND tags.name NOT IN ('Sci-Fi')
WHERE tags.id IS NULL

要获得可以有多个标签并且根本不应该有 Sci-Fi 标签的书籍,那么您可以这样做

SELECT books.id, books.name
FROM books
LEFT OUTER JOIN tags ON books.id = tags.taggable_id
GROUP BY books.id, books.name
HAVING sum(case when tags.name = 'Sci-Fi' then 1 else 0 end) = 0

【讨论】:

  • 这只是不加入带有科幻标签的书籍的标签,但仍然选择它们
【解决方案2】:

如果您在“外部”表中包含条件,这会有效地将外部联接转换为内部联接。

这是因为对于外部表中不匹配的任何行,该表中的所有列都返回为null。因此,对于任何不匹配的行,tags.name 将为空。

任何与 null 的比较都会产生null,在这种情况下意味着“不正确”,因此这些行会被 where 条件删除 - 使用内部连接它们也会如此。

您需要将该条件放入join 子句中,而不是where 子句中。

ON books.id = tags.taggable_id and tags.name NOT IN ('Sci-Fi')

由于您对没有该标签的书籍不感兴趣,您可以将外连接更改为内连接:

select *
from books
  join tags on books.id = tags.taggable_id 
           and tags.name NOT IN ('Sci-Fi')

【讨论】:

  • 这不会返回没有标签的书籍。
猜你喜欢
  • 2019-08-07
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 2013-03-10
  • 2012-09-03
相关资源
最近更新 更多