Mam takie oto 3 tabelki:
CREATE TABLE `notes` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `content` text NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `tags` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(64) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `note_tag_xref` ( `noteId` int(11) NOT NULL, `tagId` int(11) NOT NULL, PRIMARY KEY (`noteId`,`tagId`) ); INSERT INTO `notes` (`id`, `title`, `content`) VALUES (1, 'hello', 'world'), (2, 'ala', 'co ma kota'), (3, 'tomek', 'co ma psa'); INSERT INTO `note_tag_xref` (`noteId`, `tagId`) VALUES (1, 2), (2, 1), (2, 2), (3, 1), (3, 3); INSERT INTO `tags` (`id`, `name`) VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc');
Pierwsza zawiera dane (tu akurat notatki), druga tagi, po których chce wyszukiwać notatki, a trzecia jest tabelką łączącą.
Wyszukanie wszystkich notatek z posiadających tag:
SELECT n . * FROM notes n, tags t, note_tag_xref x WHERE x.tagId = t.id AND x.noteId = n.id AND t.name = 'aaa'
lub posiadający jeden z wielu tagów:
SELECT n . * FROM notes n, tags t, note_tag_xref x WHERE x.tagId = t.id AND x.noteId = n.id AND t.name IN ( 'aaa', 'bbb' )
nie jest niczym trudnym.
Problemem dla mnie jest skonstruowanie takiego zapytania, abym mógł wyszukiwać notatki posiadające wszystkie przekazane tagi (np. 'aaa' oraz 'bbb').
Fakt, mogę napisać coś takiego:
SELECT n . * FROM notes n, tags t1, tags t2, note_tag_xref x1, note_tag_xref x2 WHERE ( x1.tagId = t1.id AND x1.noteId = n.id AND t1.name = 'aaa' ) AND ( x2.tagId = t2.id AND x2.noteId = n.id AND t2.name = 'bbb' )
Ale z każdym kolejnym tagiem, po którym chce szukać, to zapytanie staje się coraz dłuższe i bardziej zagmatwane, a możliwe, że i niewydajne.
Wymyśliłem jeszcze jeden sposób:
SELECT n. * , count( * ) AS __q FROM notes n, tags t, note_tag_xref x WHERE t.name IN ( 'aaa', 'bbb' ) AND x.tagId = t.id AND x.noteId = n.id GROUP BY n.id HAVING __q =2
ale wydaje mi się on "strasznie na około", a poza tym nie pozwala mi na bardziej skomplikowane zapytania o tagi, typu: pobierz posiadające (aaa oraz bbb) lub ccc .
Może ktoś z was spotkał się z takim problemem. Może rozwiązanie jest banalne, ale nie potrafię na nie wpaść.
Będę wdzięczny za pomoc.