Witam.

Mam takie oto 3 tabelki:
  1. CREATE TABLE `notes` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `title` varchar(255) NOT NULL,
  4. `content` text NOT NULL,
  5. PRIMARY KEY (`id`)
  6. );
  7.  
  8. CREATE TABLE `tags` (
  9. `id` int(11) NOT NULL AUTO_INCREMENT,
  10. `name` varchar(64) NOT NULL,
  11. PRIMARY KEY (`id`)
  12. );
  13.  
  14. CREATE TABLE `note_tag_xref` (
  15. `noteId` int(11) NOT NULL,
  16. `tagId` int(11) NOT NULL,
  17. PRIMARY KEY (`noteId`,`tagId`)
  18. );
  19.  
  20. INSERT INTO `notes` (`id`, `title`, `content`) VALUES
  21. (1, 'hello', 'world'),
  22. (2, 'ala', 'co ma kota'),
  23. (3, 'tomek', 'co ma psa');
  24.  
  25. INSERT INTO `note_tag_xref` (`noteId`, `tagId`) VALUES
  26. (1, 2),
  27. (2, 1),
  28. (2, 2),
  29. (3, 1),
  30. (3, 3);
  31.  
  32. INSERT INTO `tags` (`id`, `name`) VALUES
  33. (1, 'aaa'),
  34. (2, 'bbb'),
  35. (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:
  1. SELECT n . *
  2. FROM notes n, tags t, note_tag_xref x
  3. WHERE x.tagId = t.id AND x.noteId = n.id AND t.name = 'aaa'

lub posiadający jeden z wielu tagów:
  1. SELECT n . *
  2. FROM notes n, tags t, note_tag_xref x
  3. WHERE x.tagId = t.id AND x.noteId = n.id AND t.name
  4. IN (
  5. 'aaa', 'bbb'
  6. )

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:
  1. SELECT n . *
  2. FROM notes n, tags t1, tags t2, note_tag_xref x1, note_tag_xref x2
  3. WHERE (
  4. x1.tagId = t1.id AND x1.noteId = n.id AND t1.name = 'aaa'
  5. ) AND (
  6. x2.tagId = t2.id AND x2.noteId = n.id AND t2.name = 'bbb'
  7. )


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:
  1. SELECT n. * , count( * ) AS __q
  2. FROM notes n, tags t, note_tag_xref x
  3. WHERE t.name
  4. IN (
  5. 'aaa', 'bbb'
  6. ) AND x.tagId = t.id AND x.noteId = n.id
  7. GROUP BY n.id
  8. 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.