Esquema propuesto
En primer lugar, aquí hay un ejemplo de mi esquema propuesto para hacer referencia a lo largo de mi publicación:
Clothes
----------
ClothesID (PK) INT NOT NULL
Name VARCHAR(50) NOT NULL
Color VARCHAR(50) NOT NULL
Price DECIMAL(5,2) NOT NULL
BrandID INT NOT NULL
...
Brand_1
--------
ClothesID (FK/PK) int NOT NULL
ViewingUrl VARCHAR(50) NOT NULL
SomeOtherBrand1SpecificAttr VARCHAR(50) NOT NULL
Brand_2
--------
ClothesID (FK/PK) int NOT NULL
PhotoUrl VARCHAR(50) NOT NULL
SomeOtherBrand2SpecificAttr VARCHAR(50) NOT NULL
Brand_X
--------
ClothesID (FK/PK) int NOT NULL
SomeOtherBrandXSpecificAttr VARCHAR(50) NOT NULL
Planteamiento del problema
Tengo una mesa de ropa que tiene columnas como nombre, color, precio, brandid, etc. para describir los atributos de una prenda de ropa en particular.
Aquí está mi problema: las diferentes marcas de ropa requieren información diferente. ¿Cuál es la mejor práctica para tratar un problema como este?
Tenga en cuenta que para mis propósitos, es necesario encontrar información específica de la marca a partir de una entrada de ropa . Esto se debe a que primero muestro la información de una entrada de ropa al usuario, después de lo cual debo usar su información específica de la marca para comprar el artículo. En resumen, tiene que haber una relación direccional entre la ropa (de) y las tablas brand_x .
Solución propuesta / actual
Para hacer frente a esto, he pensado en el siguiente esquema de diseño:
La tabla de ropa tendrá una columna de marca que puede tener valores de identificación que varían de 1 a x, donde una identificación particular corresponde a una tabla específica de la marca. Por ejemplo, el valor de identificación 1 corresponderá a la tabla marca_1 (que podría tener una columna de URL ), la identificación 2 corresponderá a la marca_2 (que podría tener una columna de proveedor ), etc.
Por lo tanto, para asociar una entrada de ropa en particular con su información específica de la marca, imagino que la lógica a nivel de aplicación se verá más o menos así:
clothesId = <some value>
brand = query("SELECT brand FROM clothes WHERE id = clothesId")
if (brand == 1) {
// get brand_1 attributes for given clothesId
} else if (brand == 2) {
// get brand_2 attributes for given clothesId
} ... etc.
Otros comentarios y pensamientos
Estoy intentando normalizar toda mi base de datos en BCNF, y aunque esto es lo que se me ocurrió, el código de aplicación resultante me hace sentir muy ansioso. No hay forma de hacer cumplir las relaciones, excepto a nivel de aplicación, y por lo tanto el diseño se siente muy hacky y, anticipo, muy propenso a errores.
Investigación
Me aseguré de mirar las entradas anteriores antes de hacer una publicación. Aquí hay una publicación con un problema casi idéntico que logré encontrar. Hice esta publicación de todos modos porque parece que la única respuesta proporcionada no tiene una solución SQL o basada en diseño (es decir, menciona OOP, herencia e interfaces).
También soy un poco novato cuando se trata de diseño de bases de datos, por lo que agradecería cualquier idea.
Parece que hay respuestas más útiles en Stack Overflow:
- aquí
- Y aquí
- Aaa y aquí (el concepto clave es: herencia de tabla de clase)
Me he referido a las soluciones allí y sugiero que otros que encuentren mi pregunta también lo hagan.
A pesar de los enlaces proporcionados anteriormente, todavía estoy buscando respuestas aquí y agradecería cualquier solución provista.
Estoy usando PostgreSQL.
fuente
Lo que está describiendo es, al menos en parte, un catálogo de productos. Tiene varios atributos que son comunes a todos los productos. Estos pertenecen a una tabla bien normalizada.
Más allá de eso, tiene una serie de atributos que son específicos de la marca (y espero que puedan ser específicos del producto). ¿Qué necesita hacer su sistema con estos atributos específicos? ¿Tiene una lógica de negocios que depende del esquema de estos atributos o simplemente los enumera en una serie de pares de "etiquetas": "valores"?
Otras respuestas están sugiriendo utilizando lo que es esencialmente un enfoque CSV (si esto es
JSON
oARRAY
o de otra manera) - Estos enfoques forego manejo moviendo el esquema de metadatos y en los propios datos de esquema relacional regular.Hay un patrón de diseño portátil para esto que se adapta muy bien a las bases de datos relacionales. Es EAV (entidad-atributo-valor). Estoy seguro de que has leído en muchos, muchos lugares que "EAV es malvado" (y lo es). Sin embargo, hay una aplicación en particular en la que los problemas con EAV no son importantes, y son los catálogos de atributos del producto.
Todos los argumentos habituales contra EAV no se aplican a un catálogo de características del producto, ya que los valores de las características del producto generalmente solo se regurgitan en una lista o, en el peor de los casos, en una tabla de comparación.
El uso de un
JSON
tipo de columna elimina su capacidad de aplicar restricciones de datos fuera de la base de datos y la fuerza a la lógica de su aplicación. Además, el uso de una tabla de atributos para cada marca tiene las siguientes desventajas:No es especialmente difícil recuperar datos sobre un producto con características específicas de la marca. Podría decirse que es más fácil crear un SQL dinámico con el modelo EAV que con el modelo de tabla por categoría. En la tabla por categoría, necesita reflexión (o su
JSON
) para descubrir cuáles son los nombres de las columnas de características. Luego puede crear una lista de elementos para una cláusula where. En el modelo EAV, seWHERE X AND Y AND Z
convierte enINNER JOIN X INNER JOIN Y INNER JOIN Z
, por lo que la consulta es un poco más complicada, pero la lógica para construir la consulta todavía está totalmente basada en tablas y será más que escalable si tiene los índices adecuados creados.Hay muchas razones para no usar EAV como un enfoque general. Esas razones no se aplican a un catálogo de características del producto, por lo que no hay nada malo con EAV en esta aplicación específica.
Sin duda, esta es una respuesta corta para un tema complejo y controvertido. He respondido preguntas similares antes y he entrado en más detalles sobre la aversión general a EAV. Por ejemplo:
Yo diría que EAV se usa con menos frecuencia últimamente de lo que solía ser, en su mayoría por buenas razones. Sin embargo, creo que tampoco se entiende bien.
fuente
Usando JSON y PostgreSQL
Creo que lo estás haciendo más difícil de lo que debe ser y te morderán más tarde. No necesita el modelo Entidad-atributo-valor a menos que realmente necesite EAV.
No hay absolutamente nada de malo en este esquema.
Ahora puedes consultarlo usando una combinación simple
Y cualquiera de los operadores JSON trabaja en una cláusula where.
Como nota al margen, no ponga las URL en la base de datos. Cambian con el tiempo. Simplemente cree una función que los tome.
o lo que sea. Si está utilizando PostgreSQL, incluso puede usar hashids .
También de nota especial,
jsonb
se almacena como binario (por lo tanto, la 'b') y también es indexable, o SARGable o como sea que los niños geniales lo llamen en estos días:CREATE INDEX ON brands USING gin ( attributes );
La diferencia aquí está en la simplicidad de la consulta.
¿Qué tal una diferente?
fuente
Una solución fácil es incluir todos los atributos posibles como columnas en la mesa principal de ropa y hacer que todas las columnas específicas de la marca puedan ser anuladas. Esta solución rompe la normalización de la base de datos, pero es muy fácil de implementar.
fuente