SQL 具有否定 WHERE 条件的 JOIN
SQL JOIN with negative WHERE condition
我有两个表 Document 和 Label(不是我的真实情况,我在类比)。一个文档可以有 N 个标签。当我需要 select 列出标签的文档时,我可以轻松做到这一点
select D.id from document D
join label L on D.id = L.document_id
where L.value in('label1','label2',...)
如何在需要没有列出标签的文档时编写查询?
当我这样做时
select D.id from document D
join label L on D.id = L.document_id
where L.value not in('label1','label2',...)
那就不行了。无论如何,所有具有多个标签且其中一个标签在列表中的文档都将被 returned。因为结合了 Document 和那些剩余标签(未列出的标签)的 raws 将简单地匹配 where 条件,所以查询将 return 我不想被 returned 的文档。
我实际上正在处理 Java Spring JPA 类型查询中的查询。我需要为我的过滤框架解决这个问题。但我认为最好先在 SQL 级别解决这个问题。
顺便说一句,为了简单起见,我们可以将 "not in" 替换为“!=”。问题还是一样
有什么简单的解决方案吗?提前谢谢你
您可以使用 LEFT JOIN
来做到这一点,您 select 所有不匹配的行:
select D.id
from document D left join label L
on D.id = L.document_id and L.value in('label1','label2',...)
where L.document_id is null
或 NOT EXISTS
:
select D.id from document D
where not exists (
select 1 from label L
where L.document_id = D.id and L.value in('label1','label2',...)
)
或 NOT IN
:
select id from document
where id not in (
select document_id from label
where value in('label1','label2',...)
)
查看简化版 demo.
如果您要查找没有标签的文档,则需要外部联接
select D.id
from document D
left join label L on D.id = L.document_id
where L.value is null
如果您想要接收没有任何给定标签的文档,那么您可以使用 not in
排除您将通过已有的肯定查询获得的 ID。
如果您想在搜索其他标签时排除某些标签,您可以使用以下方法将两者结合起来:
where id not in (
select D.id from document D
join label L on D.id = L.document_id
where L.value in('label1', ...)
) and id in (
select D.id from document D
join label L on D.id = L.document_id
where L.value in('label2', ...)
)
我有两个表 Document 和 Label(不是我的真实情况,我在类比)。一个文档可以有 N 个标签。当我需要 select 列出标签的文档时,我可以轻松做到这一点
select D.id from document D
join label L on D.id = L.document_id
where L.value in('label1','label2',...)
如何在需要没有列出标签的文档时编写查询? 当我这样做时
select D.id from document D
join label L on D.id = L.document_id
where L.value not in('label1','label2',...)
那就不行了。无论如何,所有具有多个标签且其中一个标签在列表中的文档都将被 returned。因为结合了 Document 和那些剩余标签(未列出的标签)的 raws 将简单地匹配 where 条件,所以查询将 return 我不想被 returned 的文档。
我实际上正在处理 Java Spring JPA 类型查询中的查询。我需要为我的过滤框架解决这个问题。但我认为最好先在 SQL 级别解决这个问题。
顺便说一句,为了简单起见,我们可以将 "not in" 替换为“!=”。问题还是一样
有什么简单的解决方案吗?提前谢谢你
您可以使用 LEFT JOIN
来做到这一点,您 select 所有不匹配的行:
select D.id
from document D left join label L
on D.id = L.document_id and L.value in('label1','label2',...)
where L.document_id is null
或 NOT EXISTS
:
select D.id from document D
where not exists (
select 1 from label L
where L.document_id = D.id and L.value in('label1','label2',...)
)
或 NOT IN
:
select id from document
where id not in (
select document_id from label
where value in('label1','label2',...)
)
查看简化版 demo.
如果您要查找没有标签的文档,则需要外部联接
select D.id
from document D
left join label L on D.id = L.document_id
where L.value is null
如果您想要接收没有任何给定标签的文档,那么您可以使用 not in
排除您将通过已有的肯定查询获得的 ID。
如果您想在搜索其他标签时排除某些标签,您可以使用以下方法将两者结合起来:
where id not in (
select D.id from document D
join label L on D.id = L.document_id
where L.value in('label1', ...)
) and id in (
select D.id from document D
join label L on D.id = L.document_id
where L.value in('label2', ...)
)