I have two tables Document and Label (not my real case, I am using analogy). One Document can have N Labels. When I need to select Documents that has listed labels I can do easily this
select D.id from document D
join label L on D.id = L.document_id
where L.value in('label1','label2',...)
How to write a query where I need Documents that DO NOT have listed labels? When I do this
select D.id from document D
join label L on D.id = L.document_id
where L.value not in('label1','label2',...)
then it does not work. All documents having more then one label where one of those labels is in the list will be returned anyway. Becuause raws with combination of Document and those remaining labels (not listed labels) will simply match the where condition so the query will return Documents I don't want to be returned.
I am actually working on query like that in Java Spring JPA typed queries. I need to solve this case for my filtering framework. But I think it is better to resolve this problem on SQL level first.
By the way we can replace the "not in" with "!=" for simplicity. The problem is still the same.
Any idea for a simple solution? Thank you in advance
You can do it with a LEFT JOIN
where you select all the unmatched rows:
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
or with 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',...)
)
or with NOT IN
:
select id from document
where id not in (
select document_id from label
where value in('label1','label2',...)
)
See a simplified demo.