...or if less code is your thing...
CREATE TABLE `CategoryLinks` (
`article_id` int NOT NULL,
`category_id` int NOT NULL,
PRIMARY KEY (`article_id`,`category_id`)
);
SELECT COUNT(*) FROM categorylinks;
+----------+
| COUNT(*) |
+----------+
| 107943 |
+----------+
SELECT x.article_id
FROM categorylinks x
GROUP
BY article_id
HAVING SUM(category_id IN (1,2,3)) = 3
OR SUM(category_id IN (4,5)) =2;
+------------+
| article_id |
+------------+
| 1 |
...
| 19860 |
+------------+
9573 rows in set (0.06 sec)
And the EXPLAIN...
id: 1
select_type: SIMPLE
table: x
type: index
possible_keys: NULL
key: PRIMARY
key_len: 8
ref: NULL
rows: 28719
Extra: Using index