+ notes note_id | note_title | note_uid + tags tag_id | tag_title + notes_tags nt_id | nt_note_id | nt_tag_id SELECT * FROM notes n WHERE EXISTS (SELECT 1 FROM notes_tags nt WHERE n.note_id=nt.nt_note_id AND nt.nt_tag_id=10) AND EXISTS (SELECT 1 FROM notes_tags nt2 WHERE n.note_id=nt2.nt_note_id AND nt2.nt_tag_id=11); SELECT n.*, COUNT(*) FROM notes n, notes_tags nt WHERE n.note_id-nt.nt_note_id AND nt.nt_tag_id IN (10,11) GROUP BY .... /* need to add these */ HAVING COUNT(*)=2; SELECT * FROM notes n, notes_tags nt, notes_tags nt2 WHERE n.note_id=nt.nt_note_id AND n.note_id=nt2.note_id AND nt.nt_note_id=nt2.nt_note_id /* can help the optimizer come up with a faster query */ AND nt.nt_tag_id=10 AND nt2.nt_tag_id=11 SELECT notes.* FROM notes INNER JOIN notes_tags a ON notes.note_id = a.nt_note_id AND a.nt_tag_id = 10 INNER JOIN notes_tags b ON notes.note_id = b.nt_note_id AND b.nt_tag_id = 11 SELECT * FROM notes_tags LEFT JOIN notes ON note_id = nt_note_id WHERE note_uid IN ( 1 ) AND (nt_tag_id = 10 OR nt_tag_id = 11) SELECT * FROM notes_tags LEFT JOIN notes ON note_id = nt_note_id WHERE note_uid IN ( 1 ) AND nt_tag_id IN (10, 11)