I have a cross reference table that looks like this:
id document_id subject_id
1 8 21
2 5 17
3 5 76
4 7 88
5 9 17
6 9 76
7 2 76
It matches documents to subjects. Documents can be members of more than one subject. I want to return rows from this table where a given document matches all the subjects in a given set. For example, given the set of subjects:
(17,76)
I want to return only rows for documents which match all the subjects in that set (at least) somewhere in the cross reference table. The desired output set given the above set would be:
id document_id subject_id
2 5 17
3 5 76
5 9 17
6 9 76
Notice that the last row of the table is not returned because that document only matches one of the required subjects.
What is the simplest and most efficient way to query for this in SQL?
That's a very interesting question.
I'm assuming you would like a more generalized query, but this is what I would do in the case where you always have the same number of subjects (say two):
Of course, you could add yet another INNER JOIN to add another subject ID.. But I admit it's not a very good general solution.
I assume that the natrual key of this table is document_id + subject_id, and that id is a surrogate; IOW, document_id and subject_id are unique. As such, I'm just going to pretend it doesn't exist and that a unique constraint is on the natural key.
Let's start with the obvious.
That gets you everything you want plus stuff you don't want. So all we need to do is filter out the other stuff. The "other stuff" is groups of rows having a count that is not equal to the count of the desired subjects.
Note that subject_id is removed because it doesn't participate in grouping. Taking this one step further, i'm going to add an imaginary table called subjects_i_want that contains N rows of subjects you want.
Obviously subjects_i_want could be swapped out for another subquery, temporary table, or whatever. But, once you have this list of document_id, you can use it within a subselect of a bigger query.
Or whatever.
Using Oracle (or any database that allows the with clause). This allows definition of the subject_id values exactly once.