Schéma proposé
Tout d'abord, voici un exemple de mon schéma proposé à référencer tout au long de mon post:
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
Énoncé du problème
J'ai une table de vêtements qui a des colonnes comme le nom, la couleur, le prix, le brandid et ainsi de suite pour décrire les attributs d'un vêtement particulier.
Voici mon problème: différentes marques de vêtements nécessitent des informations différentes. Quelle est la meilleure pratique pour traiter un problème comme celui-ci?
Notez que pour mes besoins, il est nécessaire de trouver des informations spécifiques à la marque à partir d'une entrée de vêtements . C'est parce que j'affiche d'abord les informations d'une entrée de vêtements à l'utilisateur, après quoi je dois utiliser ses informations spécifiques à la marque pour acheter l'article. En résumé, il doit y avoir une relation directionnelle entre les vêtements (de) et la marque_x tables .
Solution proposée / actuelle
Pour y faire face, j'ai pensé au schéma de conception suivant:
La table de vêtements aura une colonne de marque qui peut avoir des valeurs d'ID allant de 1 à x, où un ID particulier correspond à une table spécifique à la marque. Par exemple, l'id valeur 1 correspondra à la table brand_1 (qui pourrait avoir une colonne url ), l'id 2 correspondra à brand_2 (qui pourrait avoir une colonne fournisseur ), etc.
Ainsi, pour associer une entrée de vêtements particulière à ses informations spécifiques à la marque, j'imagine que la logique au niveau de l'application ressemblera à ceci:
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.
Autres commentaires et réflexions
J'essaie de normaliser l'ensemble de ma base de données dans BCNF, et bien que ce soit ce que j'ai trouvé, le code d'application qui en résulte me rend très anxieux. Il n'y a aucun moyen d'imposer des relations, sauf au niveau de l'application, et donc la conception semble très hacky et, je pense, très sujette aux erreurs.
Recherche
J'ai vérifié les entrées précédentes avant de publier un article. Voici un article avec un problème presque identique que j'ai réussi à trouver. J'ai quand même fait ce post car il semble que la seule réponse fournie ne dispose pas d'une solution SQL ou basée sur la conception (c'est-à-dire qu'elle mentionne la POO, l'héritage et les interfaces).
Je suis également un peu novice en ce qui concerne la conception de bases de données, et j'apprécierais donc toutes les informations.
Il semble qu'il y ait des réponses plus utiles sur Stack Overflow:
- Ici
- Et ici
- Aaaand ici (le concept clé étant: l'héritage de table de classe)
J'y ai fait référence aux solutions et je suggère à d'autres personnes qui trouvent ma question de le faire également.
Malgré les liens ci-dessus, je suis toujours à la recherche de réponses ici et j'apprécierais toute solution fournie!
J'utilise PostgreSQL.
la source
Ce que vous décrivez est, au moins en partie, un catalogue de produits. Vous disposez de plusieurs attributs communs à tous les produits. Ceux-ci appartiennent à un tableau bien normalisé.
Au-delà de cela, vous avez une série d'attributs spécifiques à la marque (et je pense que cela pourrait être spécifique au produit). Que doit faire votre système avec ces attributs spécifiques? Avez-vous une logique métier qui dépend du schéma de ces attributs ou les listez-vous simplement dans une série de paires "label": "value"?
D'autres réponses suggèrent d'utiliser ce qui est essentiellement une approche CSV (que ce
JSON
soitARRAY
ou non) - Ces approches renoncent à la gestion régulière du schéma relationnel en déplaçant le schéma hors des métadonnées et dans les données elles-mêmes.Il existe un modèle de conception portable qui convient très bien aux bases de données relationnelles. C'est EAV (entité-attribut-valeur). Je suis sûr que vous avez lu dans de très nombreux endroits que "l'EAV est mauvais" (et il l'est). Cependant, il existe une application particulière où les problèmes liés à l'EAV ne sont pas importants, à savoir les catalogues d'attributs de produit.
Tous les arguments habituels contre EAV ne s'appliquent pas à un catalogue de fonctionnalités de produit, car les valeurs des fonctionnalités de produit ne sont généralement régurgitées que dans une liste ou, dans le pire des cas, dans un tableau de comparaison.
L'utilisation d'un
JSON
type de colonne vous permet d'appliquer toutes les contraintes de données de la base de données et les force dans votre logique d'application. De plus, l'utilisation d'une table d'attributs pour chaque marque présente les inconvénients suivants:Il n'est pas particulièrement difficile de récupérer des données sur un produit avec des fonctionnalités spécifiques à la marque. Il est sans doute plus facile de créer un SQL dynamique en utilisant le modèle EAV que ce ne serait en utilisant le modèle de table par catégorie. Dans le tableau par catégorie, vous avez besoin d'une réflexion (ou de votre
JSON
) pour savoir quels sont les noms des colonnes d'entités. Ensuite, vous pouvez créer une liste d'éléments pour une clause where. Dans le modèle EAV, leWHERE X AND Y AND Z
devientINNER JOIN X INNER JOIN Y INNER JOIN Z
, donc la requête est un peu plus compliquée, mais la logique de construction de la requête est toujours totalement pilotée par une table et elle sera plus que suffisamment évolutive si vous avez construit les index appropriés.Il y a beaucoup de raisons de ne pas utiliser l'EAV comme approche générale. Ces raisons ne s'appliquent pas à un catalogue de fonctionnalités de produit, il n'y a donc rien de mal avec EAV dans cette application spécifique.
Certes, il s'agit d'une réponse courte à un sujet complexe et controversé. J'ai déjà répondu à des questions similaires et je suis entré dans les détails de l'aversion générale à l'EAV. Par exemple:
Je dirais que l'EAV est utilisé moins souvent ces derniers temps qu'auparavant, pour la plupart du temps pour de bonnes raisons. Cependant, je pense que ce n'est pas non plus bien compris.
la source
Utilisation de JSON et PostgreSQL
Je pense que vous rendez cela plus difficile que nécessaire et vous serez mordu plus tard. Vous n'avez pas besoin d'un modèle entité-attribut-valeur, sauf si vous avez réellement besoin d'EAV.
Il n'y a absolument rien de mal à ce schéma.
Vous pouvez maintenant l'interroger à l'aide d'une simple jointure
Et l'un des opérateurs JSON fonctionne dans une clause where.
En remarque, ne mettez pas les URL dans la base de données. Ils changent avec le temps. Créez simplement une fonction qui les prend.
ou peu importe. Si vous utilisez PostgreSQL, vous pouvez même utiliser des hachages .
A noter également,
jsonb
est stocké sous forme binaire (donc le «-b») et il est également indexable, ou SARGable ou tout ce que les enfants cool l'appellent ces jours-ci:CREATE INDEX ON brands USING gin ( attributes );
La différence ici réside dans la simplicité de la requête.
Que diriez-vous d'un autre ..
la source
Une solution simple consiste à inclure tous les attributs possibles en tant que colonnes sur la table principale des vêtements et à rendre toutes les colonnes spécifiques à la marque annulables. Cette solution rompt la normalisation de la base de données, mais est très facile à mettre en œuvre.
la source