Je crois que vous trouverez intéressant ce billet de blog: Tags: Schémas de base de données
Le problème: vous voulez avoir un schéma de base de données dans lequel vous pouvez baliser un signet (ou un article de blog ou autre) avec autant de balises que vous le souhaitez. Plus tard, vous souhaitez exécuter des requêtes pour contraindre les signets à une union ou une intersection de balises. Vous souhaitez également exclure (par exemple: moins) certaines balises du résultat de la recherche.
Solution «MySQLicious»
Dans cette solution, le schéma n'a qu'une seule table, il est dénormalisé. Ce type est appelé «solution MySQLicious» car MySQLicious importe les données del.icio.us dans une table avec cette structure.
Requête d'intersection (AND) pour "recherche + webservice + semweb":
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags LIKE "%semweb%"
Requête Union (OR) pour "recherche | webservice | semweb":
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
OR tags LIKE "%webservice%"
OR tags LIKE "%semweb%"
Requête moins pour "recherche + webservice-semweb"
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags NOT LIKE "%semweb%"
Solution «Scuttle»
Scuttle organise ses données en deux tableaux. Cette table «scCategories» est la table «tag» et a une clé étrangère vers la table «signet».
Requête d'intersection (AND) pour "bookmark + webservice + 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
Tout d'abord, toutes les combinaisons de signets-balises sont recherchées, où la balise est "signet", "webservice" ou "semweb" (c.category IN ("bookmark", "webservice", "semweb")), puis uniquement les ont obtenu les trois balises recherchées sont prises en compte (HAVING COUNT (b.bId) = 3).
Requête Union (OR) pour "bookmark | webservice | semweb": omettez
simplement la clause HAVING et vous avez union:
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
Moins (exclusion) Requête pour «signet + webservice-semweb», c'est-à-dire: signet ET webservice ET NON 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
Le fait d'omettre HAVING COUNT conduit à la requête "bookmark | webservice-semweb".
Solution «Toxi»
Toxi a proposé une structure à trois tables. Via le tableau «tagmap», les signets et les balises sont liés de n à m. Chaque balise peut être utilisée avec différents signets et vice versa. Ce schéma DB est également utilisé par wordpress. Les requêtes sont sensiblement les mêmes que dans la solution «scuttle».
Requête d'intersection (AND) pour "bookmark + webservice + 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
Requête Union (OR) pour "bookmark | webservice | 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
Moins (exclusion) Requête pour «signet + webservice-semweb», c'est-à-dire: signet ET webservice ET NON 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
Le fait d'omettre HAVING COUNT conduit à la requête "bookmark | webservice-semweb".