As Alexandre in his comment said, your design is more than problematic.
Your example is faulty too: T
- The categories 8 - 12 should have the gid 2 not 1.
- The query should return "Henry Ford" too, because he lives in the USA and works on Cars.
Following not beautiful query with a lot of joins do it (I'm sure it could be optimized, but better to optimize the database design):
SELECT *
FROM people_categories_map pmc1
INNER JOIN people_categories_map pmc2
ON pmc1.pid = pmc2.pid AND pmc1.cid <> pmc2.cid
INNER JOIN people p
ON pmc1.pid = p.id
INNER JOIN categories c1
ON pmc1.cid = c1.id
INNER JOIN categories c2
ON pmc2.cid = c2.id
INNER JOIN groups g1
ON c1.gid = g1.id
INNER JOIN groups g2
ON c2.gid = g2.id
WHERE
c1.name IN ('USA', 'FINLAND')
AND
c2.name IN ('Linux', 'Cars');
Explanation
First we do a self join of the mapping table, so we have access to both country and work of a person. It's not a real INNER JOIN, because our join condition contains an unequal-condition.
Then we join our people once, but categories and groups twice: first for country, secondly for work and filter so. You could swap those two, without losing or changing data. It's only a matter of definition.
Remark: This is not efficient, but I don't believe it is worth to optimize.
See a fiddle for the example
If you want a person only once, use
SELECT DISTINCT p.id, p.name
FROM ...