sentencias comandos sql schema tags foreign-keys entity-attribute-value

sentencias - comandos sql



¿Cómo diseñar un esquema de base de datos para admitir el etiquetado con categorías? (5)

Estoy tratando de algo así como el Diseño de la base de datos para el etiquetado , excepto que cada una de mis etiquetas se agrupan en categorías.

Por ejemplo, digamos que tengo una base de datos sobre vehículos. Digamos que en realidad no sabemos mucho sobre vehículos, por lo que no podemos especificar las columnas que tendrán todos los vehículos. Por lo tanto, "etiquetaremos" vehículos con información.

1. manufacture: Mercedes model: SLK32 AMG convertible: hardtop 2. manufacture: Ford model: GT90 production phase: prototype 3. manufacture: Mazda model: MX-5 convertible: softtop

Ahora, como puede ver, todos los automóviles están etiquetados con su fabricación y modelo, pero las otras categorías no coinciden. Tenga en cuenta que un automóvil solo puede tener uno de cada categoría. ES DECIR. Un automóvil solo puede tener un fabricante.

Quiero diseñar una base de datos para apoyar una búsqueda de todos los Mercedes, o para poder enumerar todos los fabricantes.

Mi diseño actual es algo como esto:

vehicles int vid String vin vehicleTags int vid int tid tags int tid String tag int cid categories int cid String category

Tengo todas las llaves primarias y extranjeras correctas en su lugar, excepto que no puedo manejar el caso donde cada automóvil solo puede tener un fabricante. ¿O puedo?

¿Puedo agregar una restricción de clave externa a la clave primaria compuesta en etiquetas de vehículo? ES DECIR. ¿Podría agregar una restricción tal que la clave primaria compuesta (vid, tid) solo se pueda agregar a los Títulos de vehículo solo si no hay una fila en los Títulos de vehículo, de modo que para el mismo video, todavía no hay un tid en el el mismo cid?

Mi conjetura es no. Creo que la solución a este problema es agregar una columna cid a vehicleTags, y crear la nueva clave primaria compuesta (vid, cid). Se vería así:

vehicleTags int vid int cid int tid

Esto evitaría que un automóvil tenga dos fabricantes, pero ahora he duplicado la información de que el tid está en cid.

¿Cuál debería ser mi esquema?

Tom notó este problema en mi esquema de base de datos en mi pregunta anterior, ¿Cómo se hacen muchas combinaciones externas de tabla?

EDITAR
Sé que en el ejemplo, la fabricación debería ser realmente una columna en la mesa del vehículo, pero digamos que no se puede hacer eso. El ejemplo es solo un ejemplo.


Una forma sería repensar un poco su esquema, normalizando las claves de los valores:

vehicles int vid string vin tags int tid int cid string key categories int cid string category vehicleTags int vid int tid string value

Ahora todo lo que necesita es una restricción única en vehicleTags(vid, tid) .

Alternativamente, hay formas de crear restricciones más allá de las claves externas simples: dependiendo de su base de datos, ¿puede escribir una restricción personalizada o un activador de inserción / actualización para imponer la exclusividad de la etiqueta del vehículo?


Creo que su solución es simplemente agregar una columna de fabricante a su tabla de vehículos. Es un atributo que usted sabe que todos los vehículos tendrán (es decir, los automóviles no aparecen espontáneamente por sí mismos) y al convertirlo en una columna en la tabla de su vehículo, usted resuelve el problema de tener un solo fabricante para cada vehículo. Este enfoque se aplicaría a cualquier atributo que sepa que será compartido por todos los vehículos. Luego puede implementar el sistema de etiquetado para los otros atributos que no son universales.

Así que tomando de su ejemplo, la mesa del vehículo sería algo así como:

vehicle vid vin make model


Esta es otra variación más en el diseño Entity-Attribute-Value .

Una tabla EAV más reconocible se ve así:

CREATE TABLE vehicleEAV ( vid INTEGER, attr_name VARCHAR(20), attr_value VARCHAR(100), PRIMARY KEY (vid, attr_name), FOREIGN KEY (vid) REFERENCES vehicles (vid) );

Algunas personas obligan a attr_name a hacer referencia a una tabla de búsqueda de nombres de atributos predefinidos, para limitar el caos.

Lo que has hecho es simplemente extender una tabla EAV en tres tablas, pero sin mejorar el orden de tus metadatos:

CREATE TABLE vehicleTag ( vid INTEGER, cid INTEGER, tid INTEGER, PRIMARY KEY (vid, cid), FOREIGN KEY (vid) REFERENCES vehicles(vid), FOREIGN KEY (cid) REFERENCES categories(cid), FOREIGN KEY (tid) REFERENCES tags(tid) ); CREATE TABLE categories ( cid INTEGER PRIMARY KEY, category VARCHAR(20) -- "attr_name" ); CREATE TABLE tags ( tid INTEGER PRIMARY KEY, tag VARCHAR(100) -- "attr_value" );

Si vas a utilizar el diseño EAV, solo necesitas el vehicleTags Tablas y tablas de categories .

CREATE TABLE vehicleTag ( vid INTEGER, cid INTEGER, -- reference to "attr_name" lookup table tag VARCHAR(100, -- "attr_value" PRIMARY KEY (vid, cid), FOREIGN KEY (vid) REFERENCES vehicles(vid), FOREIGN KEY (cid) REFERENCES categories(cid) );

Pero tenga en cuenta que está mezclando datos con metadatos . Pierdes la habilidad de aplicar ciertas restricciones a tu modelo de datos.

  • ¿Cómo puede hacer que una de las categorías sea obligatoria (una columna convencional usa una restricción NOT NULL )?
  • ¿Cómo puede usar los tipos de datos SQL para validar algunos de sus valores de etiqueta? No puedes, porque estás usando una cadena larga para cada valor de etiqueta. ¿Esta cadena es lo suficientemente larga para cada etiqueta que necesitarás en el futuro? No puedes decir.
  • ¿Cómo puede restringir algunas de sus etiquetas a un conjunto de valores permitidos (una tabla convencional utiliza una clave externa para una tabla de búsqueda)? Este es su ejemplo "softtop" vs. "soft top". Pero no puede establecer una restricción en la columna de tag porque esa restricción se aplicaría a todos los demás valores de etiquetas para otras categorías. También debe restringir el tamaño del motor y el color de la pintura a la "parte superior blanda".

Las bases de datos SQL no funcionan bien con este modelo. Es extremadamente difícil acertar, y consultarlo se vuelve muy complejo. Si continúa utilizando SQL, será mejor que modele las tablas de manera convencional, con una columna por atributo. Si necesita tener "subtipos", defina una tabla subordinada por subtipo ( herencia de tabla de clase ) o use herencia de tabla única . Si tiene una variación ilimitada en los atributos por entidad, utilice el LOB serializado .

Otra tecnología que está diseñada para este tipo de modelos de datos fluidos y no relacionales es una Base de datos semántica que almacena datos en RDF y se consulta con SPARQL . Una solución gratuita es Sesame .


Necesitaba resolver este problema exacto (el mismo dominio general y todo, partes de automóviles). Descubrí que la mejor solución al problema era usar Lucene / Xapian / Ferret / Sphinx o cualquier indexador de texto completo que prefiriera. Mucho mejor desempeño que lo que SQL puede ofrecer.

Hoy en día, casi nunca termino construyendo una aplicación web respaldada por una base de datos que no involucre un indexador de texto completo. Este problema y el problema general de la búsqueda surgen con demasiada frecuencia para omitir los indizadores de su caja de herramientas.


Necesitaba resolver este problema exacto (el mismo dominio general y todo, partes de automóviles). Descubrí que la mejor solución al problema era usar Lucene / Xapian / Ferret / Sphinx o cualquier indexador de texto completo que prefiriera. Mucho mejor desempeño que lo que SQL puede ofrecer.