You're making a common mistake in database design, by storing a comma-separated list of tag id's. It's not a surprise that performing efficient queries against this is a blocker for you.
What you need is to model the mapping between objects and tags in a separate table.
CREATE TABLE Tagged (
object_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (object_id, tag_id),
FOREIGN KEY (object_id) REFERENCES Objects(object_id),
FOREIGN KEY (tag_id) REFERENCES Tags(tag_id)
);
Insert one row for each object/tag pairing. Of course, this means you have several rows for each object_id
, but that's okay.
You can query for all objects that have tags 3,4,5:
SELECT DISTINCT object_id
FROM Tagged
WHERE tag_id IN (3, 4, 5);
But this matches object1, which you don't want. You want to exclude objects that have other tags not in 3,4,5.
SELECT DISTINCT t1.object_id
FROM Tagged t1
LEFT OUTER JOIN Tagged t2
ON (t1.object_id = t2.object_id AND t2.tag_id NOT IN (3, 4, 5))
WHERE t1.tag_id IN (3, 4, 5)
AND t2.object_id IS NULL;