Думаю, вам будет интересно это сообщение в блоге: Теги: схемы баз данных
Проблема: вы хотите иметь схему базы данных, в которой вы можете пометить закладку (или сообщение в блоге или что-то еще) с любым количеством тегов. Позже вы захотите выполнить запросы, чтобы ограничить закладки объединением или пересечением тегов. Вы также хотите исключить (скажем: минус) некоторые теги из результатов поиска.
«MySQLicious» решение
В этом решении в схеме всего одна таблица, она денормализована. Этот тип называется «решением MySQLicious», потому что MySQLicious импортирует данные del.icio.us в таблицу с такой структурой.
Пересечение (И) Запрос «поиск + веб-сервис + semweb»:
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags LIKE "%semweb%"
Union (OR) Запрос для «search | webservice | semweb»:
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
OR tags LIKE "%webservice%"
OR tags LIKE "%semweb%"
Минус-запрос для «search + webservice-semweb»
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags NOT LIKE "%semweb%"
Раствор «Скаттл»
Скаттл систематизирует свои данные в двух таблицах. Эта таблица scCategories является таблицей «тегов» и имеет внешний ключ к таблице «закладок».
Пересечение (И) Запрос для «закладка + веб-сервис + semweb»:
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
HAVING COUNT( b.bId )=3
Сначала ищутся все комбинации закладки и тега, где тегом является «закладка», «веб-сервис» или «semweb» (c.category IN («закладка», «веб-сервис», «semweb»)), а затем только закладки, которые учитываются все три найденных тега (HAVING COUNT (b.bId) = 3).
Union (OR) Запрос для «bookmark | webservice | semweb»:
просто опустите предложение HAVING, и у вас будет union:
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
Минус (исключение) Запрос «закладка + веб-сервис-semweb», то есть: закладка И веб-сервис, А НЕ semweb.
SELECT b. *
FROM scBookmarks b, scCategories c
WHERE b.bId = c.bId
AND (c.category IN ('bookmark', 'webservice'))
AND b.bId NOT
IN (SELECT b.bId FROM scBookmarks b, scCategories c WHERE b.bId = c.bId AND c.category = 'semweb')
GROUP BY b.bId
HAVING COUNT( b.bId ) =2
Отсутствие HAVING COUNT приводит к запросу «закладка | webservice-semweb».
Раствор «Токси»
Toxi придумал структуру из трех столов. Через таблицу «tagmap» закладки и теги связаны n-к-m. Каждый тег можно использовать вместе с разными закладками и наоборот. Эта схема БД также используется wordpress. Запросы такие же, как и в решении «scuttle».
Пересечение (И) Запрос «закладка + веб-сервис + semweb»
SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
HAVING COUNT( b.id )=3
Union (OR) Запрос для «закладка | веб-сервис | semweb»
SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
Минус (исключение) Запрос «закладка + веб-сервис-semweb», то есть: закладка И веб-сервис, А НЕ semweb.
SELECT b. *
FROM bookmark b, tagmap bt, tag t
WHERE b.id = bt.bookmark_id
AND bt.tag_id = t.tag_id
AND (t.name IN ('Programming', 'Algorithms'))
AND b.id NOT IN (SELECT b.id FROM bookmark b, tagmap bt, tag t WHERE b.id = bt.bookmark_id AND bt.tag_id = t.tag_id AND t.name = 'Python')
GROUP BY b.id
HAVING COUNT( b.id ) =2
Отсутствие HAVING COUNT приводит к запросу «закладка | webservice-semweb».