Creo que encontrará interesante esta publicación de blog: Etiquetas: esquemas de base de datos
El problema: desea tener un esquema de base de datos en el que pueda etiquetar un marcador (o una publicación de blog o lo que sea) con tantas etiquetas como desee. Luego, desea ejecutar consultas para restringir los marcadores a una unión o intersección de etiquetas. También desea excluir (digamos: menos) algunas etiquetas del resultado de la búsqueda.
Solución "MySQLicious"
En esta solución, el esquema tiene solo una tabla, está desnormalizado. Este tipo se llama “solución MySQLicious” porque MySQLicious importa datos del.icio.us a una tabla con esta estructura.
Consulta de intersección (Y) para "búsqueda + servicio web + semweb":
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags LIKE "%semweb%"
Consulta de unión (OR) para "búsqueda | servicio web | semweb":
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
OR tags LIKE "%webservice%"
OR tags LIKE "%semweb%"
Menos consulta para "búsqueda + servicio web-semweb"
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags NOT LIKE "%semweb%"
Solución "Scuttle"
Scuttle organiza sus datos en dos tablas. Esa tabla “scCategories” es la tabla de “etiquetas” y tiene una clave externa para la tabla de “marcadores”.
Consulta de intersección (Y) para "marcador + servicio web + 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
Primero, se buscan todas las combinaciones de marcador-etiqueta, donde la etiqueta es "marcador", "servicio web" o "semweb" (c.category IN ('marcador', 'servicio web', 'semweb')), luego solo los marcadores que tienen las tres etiquetas buscadas se tienen en cuenta (HAVING COUNT (b.bId) = 3).
Unión (OR) Consulta de "marcador | servicio web | semweb":
simplemente omita la cláusula HAVING y tendrá unión:
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
Menos (exclusión) Consulta para “marcador + servicio web-semweb”, es decir: marcador Y servicio web Y NO 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
Si se omite HAVING COUNT, aparecerá la consulta de "marcador | webservice-semweb".
Solución "Toxi"
Toxi ideó una estructura de tres mesas. A través de la tabla "mapa de etiquetas", los marcadores y las etiquetas están relacionados de n-a-m. Cada etiqueta se puede utilizar junto con diferentes marcadores y viceversa. Wordpress también utiliza este esquema de base de datos. Las consultas son prácticamente las mismas que en la solución “scuttle”.
Consulta de intersección (Y) para "marcador + servicio web + 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
Consulta de unión (OR) para "marcador | servicio web | 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
Menos (exclusión) Consulta para “marcador + servicio web-semweb”, es decir: marcador Y servicio web Y NO 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
Si se omite HAVING COUNT, aparecerá la consulta de "marcador | webservice-semweb".