Cette question porte sur la façon de concevoir une base de données, il peut s'agir de bases de données relationnelles / nosql, en fonction de la meilleure solution
Étant donné une exigence où vous devrez créer un système qui impliquera une base de données pour suivre "Société" et "Utilisateur". Un seul utilisateur appartiennent toujours à un seul société
- Un utilisateur peut appartenir à une société
- Une entreprise peut avoir plusieurs utilisateurs
La conception de la table "Entreprise" est assez simple. La société aura les attributs / colonnes suivants: (restons simples)
ID, COMPANY_NAME, CREATED_ON
premier scénario
Simple et direct, les utilisateurs ont tous le même attribut, donc cela peut être facilement fait dans un style relationnel, table utilisateur:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CREATED_ON
deuxième scénario
Que se passe-t-il si différentes entreprises souhaitent stocker un attribut de profil différent pour leur utilisateur. Chaque entreprise aura un ensemble défini d'attributs qui s'appliqueraient à tous les utilisateurs de cette entreprise.
Par exemple:
- La société A souhaite stocker: LIKE_MOVIE (booléen), LIKE_MUSIC (booléen)
- Société B veut magasin: FAV_CUISINE (String)
- La société C veut stocker: OWN_DOG (Boolean), DOG_COUNT (int)
approche 1
la voie de la force brute est d'avoir un seul schéma pour l'utilisateur et leur laisser quand ils ne nulls appartiennent à la société:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, LIKE_MOVIE, LIKE_MUSIC, FAV_CUISINE, OWN_DOG, DOG_COUNT, CREATED_ON
Ce qui est un peu méchante parce que vous finirez avec beaucoup de lignes NULLS et utilisateurs qui ont des colonnes qui ne sont pas pertinents pour les (p. Tous les utilisateurs appartenant à la société A a des valeurs NULL pour FAV_CUISINE, OWN_DOG, DOG_COUNT)
approche 2
une deuxième approche, est d'avoir « champ forme libre »:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_1, CUSTOM_2, CUSTOM_3, CREATED_ON
Ce qui serait désagréable en soi puisque vous n'avez aucune idée de ce que sont les champs personnalisés, le type de données ne reflétera pas les valeurs stockées (par exemple, nous stockons la valeur int en tant que VARCHAR).
approche 3
J'ai cherché dans le champ PostgreSQL JSON, auquel cas vous aurez:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_PROFILE_JSON, CREATED_ON
Dans ce cas, comment pourriez-vous appliquer différents schémas à un utilisateur? Un utilisateur avec la société A aura un schéma qui ressemble à
{"LIKE_MOVIE":"boolean", "LIKE_MUSIC": "boolean"}
Alors qu'un utilisateur avec la société C aura un schéma différent:
{"OWN_DOG ":"boolean", "DOG_COUNT": "int"}
Comment dois-je résoudre ce problème?
solution relationnelle? solution NoSQL?
Edit: J'ai aussi pensé à une table « CUSTOM_PROFILE » qui l' essentiel stocker des attributs d' utilisateur dans les lignes plutôt que des colonnes.
Il y a 2 problèmes avec cette approche:
1) Les données grandissent par utilisateur croissent sous forme de lignes plutôt que de colonnes - et cela signifie pour obtenir une image complète de l'utilisateur, beaucoup de jointures doivent être effectuées, plusieurs jointures dans le tableau "profil personnalisé" sur les différents attributs personnalisés
2) La valeur des données est toujours stockée en tant que VARCHAR pour être générique, même si nous savons que les données sont censées être des nombres entiers ou booléens, etc.
la source
Réponses:
Les deux précédents exemples à la fois exiger que vous apportez des modifications au schéma de la portée de l'application augmente en plus la solution « custom_column » est difficile à étendre et à entretenir. Finalement, vous finirez avec Custom_510 puis imaginer combien ce tableau terrible consiste à travailler avec.
D'abord Utilisons votre schéma entreprises.
Ensuite, nous allons utiliser aussi les utilisateurs schémas de haut niveau des attributs nécessaires qui seront utilisées par / partagées toutes les sociétés.
Voici donc une valeur d'exemple de la colonne d'attribut serait « LikeMusic »:
Ensuite, nous définissons une table userattributes qui contiendra des valeurs d'attributs utilisateur
Cela peut être modifié de plusieurs façons pour améliorer les performances. Vous pouvez utiliser plusieurs tables pour userattributes faire de chacun spécifique au type de données stockées dans la valeur ou tout simplement le laisser comme VARCHAR et travailler avec elle comme un magasin keyvalue.
Vous pouvez également déplacer COMPANYID hors de la table UserAttributeDefiniton et dans une table de référence croisée pour l'épreuvage avenir.
la source
Utilisez une base de données NoSQL. Il y aurait des documents d'entreprise et d'utilisateur. Les utilisateurs auraient une partie de leur schéma créée dynamiquement sur la base d'un modèle d'utilisateur (texte pour indiquer les champs / types pour cette entreprise.
Voici à quoi cela pourrait ressembler dans quelque chose comme Firebase.com. Vous devriez apprendre à le faire dans celui que vous choisissez.
la source
Si vous allez fréquemment rencontrer des demandes de champs personnalisés, je les modéliserais de manière assez similaire à la base de données. Créer une table qui contient les métadonnées sur chaque champ personnalisé, CompanyCustomField (à qui il appartient, le type de données, etc.) et une autre table CompanyCustomFieldValues qui contient le CustomerId, FieldID et la valeur. Si vous utilisez quelque chose comme Microsoft Sql Server, la colonne de valeur devrait être un type de données sql_variant.
Bien sûr, cela n'est pas facile car vous aurez besoin d'une interface qui permet aux administrateurs de définir des champs personnalisés pour chaque client, et d'une autre interface qui utilise réellement ces métadonnées pour créer une interface utilisateur pour collecter les valeurs des champs. Et si vous avez d'autres exigences, telles que le regroupement des champs ou la nécessité de faire un type de champ de liste de sélection, vous devrez l'accompagner de plus de métadonnées / autres tables (par exemple, CompanyCustomFieldPickListOptions).
Ce n'est pas anodin, mais il a l'avantage de ne pas nécessiter de modifications de base de données / de code pour chaque nouveau champ personnalisé. Toutes les autres fonctionnalités des champs personnalisés devront également être codées (par exemple, si vous souhaitez valider regex une valeur de chaîne, ou autoriser uniquement les dates entre certaines plages, ou si vous devez activer un champ personnalisé basé sur une autre valeur de champ personnalisé ).
la source
Une alternative aux autres réponses est d'avoir une table appelée profile_attrib, ou similaire que le schéma est entièrement géré par votre application.
À mesure que des attributs personnalisés sont ajoutés
ALTER TABLE profile_attrib ADD COLUMN like_movie TINYINT(1)
, vous pouvez interdire leur suppression. Cela minimiserait votre adhésion, tout en offrant une flexibilité.Je suppose que le compromis bit est l'application a besoin maintenant des privilèges alter table à la base de données, et vous devez être intelligent au sujet désinfectante les noms de colonnes.
la source
[^\w-]+
devrait assez bien le faire, ne pas laisser tout ce qui est pas0-9A-Za-z_-
--mais oui, désinfectante est un must ici pour se protéger contre la bêtise ou la méchanceté.Votre question a de nombreuses solutions potentielles. Une solution consiste à stocker les attributs supplémentaires au format XML. Le XML peut être stocké sous forme de texte ou si vous utilisez une base de données qui supporte les types de XML comme XML (SQL Server). Le stockage en tant que texte limite votre capacité d'interrogation (comme la recherche sur un attribut personnalisé), mais si le stockage et la récupération sont tous vos besoins, c'est une bonne solution. Si on a besoin de requête, puis stocker le XML comme un type XML serait une meilleure option (bien que ce soit plus spécifique du fournisseur).
Cela donnera une la possibilité de stocker un nombre illimité d'attributs à un client avec juste l'ajout d'une colonne d'addition sur la table des clients. On pourrait stocker les attributs sous forme de hachage ou de dictionnaire, on perdra la sécurité du type car tout sera une chaîne pour commencer, mais si l'on applique une chaîne de format standard pour les dates, les nombres, les booléens, cela fonctionnera bien.
Pour plus d'informations:
https://msdn.microsoft.com/en-us/library/hh403385.aspx
@ La réponse de WalterMitty est également valable, bien que si l'on a beaucoup de clients avec des attributs différents, on puisse se retrouver avec de nombreuses tables si l'on suit le modèle d'héritage. Cela dépend du nombre d'attributs personnalisés partagés entre les clients.
la source
Vous devez normaliser votre base de données de manière à disposer de 3 tables différentes pour chaque type de profil d'entreprise. En utilisant votre exemple, vous auriez des tables avec des colonnes:
Cette approche suppose que vous connaîtrez à l'avance la forme des informations qu'une entreprise souhaite stocker et qu'elle ne changera pas souvent. Si la forme des données est inconnue au moment de la conception, il serait probablement préférable d'utiliser ce champ JSON ou une base de données nosql.
la source
Pour une raison ou une autre, les bases de données sont le seul domaine dans lequel l'effet de plate-forme interne apparaît le plus souvent. Ceci est juste un autre cas de pop-up anti-motif.
Dans ce cas, vous essayez de combattre la solution naturelle et correcte. Les utilisateurs de la société A ne sont pas des utilisateurs de la société B et doivent avoir leurs propres tables pour leurs propres champs.
Votre fournisseur de base de données ne vous facture pas à la table et vous n'avez pas besoin de deux fois l'espace disque pour deux fois les tables (en fait, avoir deux tables est plus efficace car vous ne stockez pas les attributs de A pour les utilisateurs de B. Même en stockant uniquement des valeurs NULL prend de la place).
Bien sûr, s'il y a suffisamment de champs communs, vous pouvez les factoriser dans une table d'utilisateurs partagée et avoir une clé étrangère dans chacune des tables d'utilisateurs spécifiques à l'entreprise. Il s'agit d'une structure si simple qu'aucun optimiseur de requête de base de données ne lutte avec elle. Tout JOIN nécessaire est trivial.
la source
Ma solution suppose que vous appelleriez cette requête à partir d'un programme et que vous devriez pouvoir effectuer un post-traitement. Vous pouvez avoir les colonnes suivantes:
CUSTOM_VALUES sera de type chaîne stockant la paire clé / valeur. la clé sera le nom de la colonne et la valeur sera la valeur de la colonne, par exemple
dans ces CUSTOM_VALUES, vous n'enregistrerez que les informations existantes. Lorsque vous interrogez à partir d'un programme, vous pouvez diviser cette chaîne et l'utiliser.
J'ai utilisé cette logique et cela fonctionne bien, c'est juste que vous devrez appliquer une logique de filtrage dans le code et non dans la requête.
la source