I have to say - I'm stumped. I cannot think of any solution that would come even close. I would try looking for a solution in these directions:
- User-defined aggregate functions. Maybe you can make a function that takes as an argument the desired expression (in a simplified syntax) and the rows for a single person. The function then parses the expression and matches it against the rows. Hmm... maybe MySQL includes some concatenating aggregate function and a regex matching function? This might be a solution then (though probably not a very fast one).
- Analytic functions. I don't pretend that I understand them, but as much as I know about them, I think they are generally in this direction. Although I don't know if there will be a function that will suit this need.
Added:
Ahh, I think I got it! Although I think the performance will be miserable. But this will work! For example, if you have the requirement to search for 1 AND 2 AND (3 OR 4)
then you would write:
SELECT
*
FROM
Persons A
WHERE
EXISTS (Select * from PersonCriteria B WHERE A.PersonID=B.PersonID AND CriteriaID=1)
AND
EXISTS (Select * from PersonCriteria B WHERE A.PersonID=B.PersonID AND CriteriaID=2)
AND
(
EXISTS (Select * from PersonCriteria B WHERE A.PersonID=B.PersonID AND CriteriaID=3)
OR
EXISTS (Select * from PersonCriteria B WHERE A.PersonID=B.PersonID AND CriteriaID=4)
)
Added 2: Here's another one, though the performance will likely be even worse:
SELECT p.* FROM Person p
JOIN (select PersonID from PersonCriteria WHERE CriteriaID=1) c1 ON p.PersonID=c1.PersonID
JOIN (select PersonID from PersonCriteria WHERE CriteriaID=2) c2 ON p.PersonID=c2.PersonID
JOIN (select PersonID from PersonCriteria WHERE CriteriaID IN (3,4)) c3 ON p.PersonID=c3.PersonID
Added 3: This is a variation of No. 2, but this might actually have a chance of a decent performance!
SELECT p.* FROM
Person p
JOIN PersonCriteria c1 on (p.PersonID=c1.PersonID AND c1.CriteriaID=1)
JOIN PersonCriteria c2 on (p.PersonID=c2.PersonID AND c2.CriteriaID=2)
JOIN PersonCriteria c3 on (p.PersonID=c3.PersonID AND c3.CriteriaID IN (3,4))
If you add an index to PersonCriteria on columns (PersonID,CriteriaID) (exactly in this order!), then I think it's about as fast as you're going to get in any case.