これは、「set-within-sets」クエリの例です。最も一般的なアプローチはgroup by
、ロジックを使用してhaving
句に入れることです。あなたの場合:
SELECT B.name, B.author, B.id, B.finished, B.manual
FROM books B INNER JOIN
xrefbookstags XRBT
ON XRBT.idBooks = B.id JOIN
tags T
ON XRBT.idTags = T.id
group by B.name, B.author, B.id, B.finished, B.manual
having sum(case when t.name = 'novel' then 1 else 0 end) > 0 and
sum(case when t.name = 'biography' then 1 else 0 end) > 0 and
sum(case when t.name not in ('novel', 'biography') then 1 else 0 end) = 0;
ロジックは次のとおりです。最初の句は、少なくとも 1 つのタグが である場合に true です'novel'
。少なくとも 1 つの句が存在する場合、2 番目の句は true に'biography'
なり、他のタグがない場合、3 番目の句は true になります。
これは簡単に一般化できます。これらの 2 つのタグがあり、他のタグを持つ可能性のある書籍が必要な場合は、3 番目の句を省略します。
having sum(case when t.name = 'novel' then 1 else 0 end) > 0 and
sum(case when t.name = 'biography' then 1 else 0 end) > 0;
どちらか一方の本が必要な場合:
having sum(case when t.name = 'novel' then 1 else 0 end) > 0 or
sum(case when t.name = 'biography' then 1 else 0 end) > 0;
これらの 2 つに加えて「歴史的」な本が必要な場合は、次のように追加します。
having sum(case when t.name = 'novel' then 1 else 0 end) > 0 and
sum(case when t.name = 'biography' then 1 else 0 end) > 0 and
sum(case when t.name = 'historical' then 1 else 0 end) > 0;
そして、あなたがそれを望んでいたが、料理についてではなかった場合:
having sum(case when t.name = 'novel' then 1 else 0 end) > 0 and
sum(case when t.name = 'biography' then 1 else 0 end) > 0 and
sum(case when t.name = 'historical' then 1 else 0 end) > 0 and
sum(case when t.name = 'cooking' then 1 else 0 end) = 0;
編集:
一致させたいタグのコンマ区切りリストがある場合は、次のことができます。
having sum(case when ','+@List+',' not like '%,'+t.name+',%' then 1 else 0 end) = 0 and
count(distinct t.name) = 1 + len(@list) - len(replace(@list, ',', ''))
最初の節は、すべてのタグがリストにあることを示しています。2 番目は、タグの長さがリストの長さであることを示しています。
これは基本的に疑似コードです。データベースが異なれば、len()
関数の名前も異なり、文字列を連結する方法も異なり、変数値を表現する方法も異なります。しかし、意図は明確でなければなりません。