SQL ПРИСОЕДИНЯЙТЕСЬ с отрицательным условием ГДЕ - PullRequest
0 голосов
/ 24 марта 2020

У меня есть две таблицы Document и Label (не в моем случае, я использую аналогию). Один документ может иметь N меток. Когда мне нужно выбрать Документы, на которых есть метки, я легко могу это сделать

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',...)

, тогда это не работает. Все документы, имеющие более одной метки, где одна из этих меток находится в списке, будут возвращены в любом случае. Потому что r aws с комбинацией Document и тех оставшихся меток (не перечисленных меток) будет просто соответствовать условию where, поэтому запрос вернет документы, которые я не хочу возвращать.

Я фактически работаю над запрос подобный этому в Java Spring JPA типизированных запросах. Мне нужно решить этот случай для моей системы фильтрации. Но я думаю, что лучше сначала решить эту проблему на уровне SQL.

Кстати, для простоты мы можем заменить "не в" на "! =". Проблема все та же.

Есть идеи для простого решения? Заранее спасибо

Ответы [ 3 ]

2 голосов
/ 24 марта 2020

Вы можете сделать это с LEFT JOIN, где вы выбираете все несопоставленные строки:

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',...)
)

См. Упрощенную демонстрацию .

0 голосов
/ 24 марта 2020

Если вы хотите получать документы, которые не имеют какой-либо из указанных меток, вы можете исключить идентификаторы, которые вы получите с положительным запросом, с помощью not in. Если вы хотите исключить некоторые метки при поиске других, вы можете объединить оба с помощью:

    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', ...)
    )
0 голосов
/ 24 марта 2020

Если вы ищете документы без меток, вам нужно внешнее объединение

select D.id 
from document D
left join label L on  D.id = L.document_id
where L.value is null
...