Gérer une information individuelle
En supposant que, dans votre domaine d'activité,
- un utilisateur peut avoir zéro ou un ou plusieurs amis ;
- un ami doit d'abord être enregistré en tant qu'utilisateur ; et
- vous rechercherez et / ou ajouterez et / ou supprimerez et / ou modifierez les valeurs uniques d'une liste d'amis ;
puis chaque donnée spécifique collectée dans la Friendlist_IDs
colonne à plusieurs valeurs représente une information distincte qui a une signification très exacte. Par conséquent, ladite colonne
- implique un groupe approprié de contraintes explicites, et
- ses valeurs ont le potentiel d'être manipulées individuellement au moyen de plusieurs opérations relationnelles (ou de leurs combinaisons).
Réponse courte
Par conséquent, vous devez conserver chacune des Friendlist_IDs
valeurs dans (a) une colonne qui accepte exclusivement une seule valeur par ligne dans (b) un tableau qui représente le type d'association au niveau conceptuel qui peut avoir lieu entre les utilisateurs , c'est-à-dire une amitié - comme Je vais illustrer dans les sections suivantes—.
De cette façon, vous pourrez gérer (i) ladite table comme une relation mathématique et (ii) ladite colonne comme un attribut de relation mathématique - autant que MySQL et son dialecte SQL le permettent, bien sûr -.
Pourquoi?
Parce que le modèle relationnel de données , créé par Dr. E. F. Codd , exige d'avoir des tables qui sont composées de colonnes qui contiennent exactement une valeur du domaine ou du type applicable par ligne; par conséquent, déclarer un tableau avec une colonne qui peut contenir plus d'une valeur du domaine ou du type en question (1) ne représente pas une relation mathématique et (2) ne permettrait pas d'obtenir les avantages proposés dans le cadre théorique susmentionné.
Modélisation des amitiés entre utilisateurs : définir d'abord les règles de l'environnement commercial
Je recommande fortement de commencer à façonner une base de données délimitant - avant toute autre chose - le schéma conceptuel correspondant en vertu de la définition des règles commerciales pertinentes qui, entre autres facteurs, doivent décrire les types d'interrelations qui existent entre les différents aspects d'intérêt, à savoir , les types d'entités applicables et leurs propriétés ; par exemple:
- Un utilisateur est principalement identifié par son UserId
- Un utilisateur est alternativement identifié par la combinaison de son FirstName , LastName , Sexe et Date de naissance
- Un utilisateur est alternativement identifié par son nom d' utilisateur
- Un utilisateur est le demandeur d' amitiés zéro à un ou plusieurs
- Un utilisateur est le destinataire d' amitiés nulles
- Une amitié est principalement identifiée par la combinaison de son RequesterId et de son AddresseeId
Diagramme expositoire IDEF1X
De cette manière, j'ai pu dériver le diagramme IDEF1X 1 illustré à la figure 1 , qui intègre la plupart des règles formulées précédemment:
Comme représenté, le demandeur et le destinataire sont des dénotations qui expriment les rôles effectués par les utilisateurs spécifiques qui participent à une amitié donnée .
Cela étant, le type d'entité Amitié représente un type d'association de ratio de cardinalité plusieurs à plusieurs (M: N) qui peut impliquer différentes occurrences du même type d'entité, c'est-à-dire Utilisateur . À ce titre, il s'agit d'un exemple de la construction classique connue sous le nom de «nomenclature» ou «explosion de pièces».
1 La définition d'intégration pour la modélisation de l'information ( IDEF1X ) est une technique hautement recommandable qui a été établie en tant que norme en décembre 1993 par le National Institute of Standards and Technology (NIST)des États-Unis. Il est solidement fondé sur (a) les premiers éléments théoriques rédigés par le seul auteur du modèle relationnel, c'est-à-dire le Dr EF Codd ; sur (b) la vue entité-relation des données, développée par le Dr PP Chen ; et également sur (c) la technique de conception de bases de données logiques, créée par Robert G. Brown.
Conception logique illustrative SQL-DDL
Ensuite, à partir du diagramme IDEF1X présenté ci-dessus, déclarer un arrangement DDL comme celui qui suit est beaucoup plus «naturel»:
-- You should determine which are the most fitting
-- data types and sizes for all the table columns
-- depending on your business context characteristics.
-- At the physical level, you should make accurate tests
-- to define the mostconvenient INDEX strategies based on
-- the pertinent query tendencies.
-- As one would expect, you are free to make use of
-- your preferred (or required) naming conventions.
CREATE TABLE UserProfile ( -- Represents an independent entity type.
UserId INT NOT NULL,
FirstName CHAR(30) NOT NULL,
LastName CHAR(30) NOT NULL,
BirthDate DATE NOT NULL,
GenderCode CHAR(3) NOT NULL,
Username CHAR(20) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT UserProfile_PK PRIMARY KEY (UserId),
CONSTRAINT UserProfile_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
FirstName,
LastName,
GenderCode,
BirthDate
),
CONSTRAINT UserProfile_AK2 UNIQUE (Username) -- Single-column ALTERNATE KEY.
);
CREATE TABLE Friendship ( -- Stands for an associative entity type.
RequesterId INT NOT NULL,
AddresseeId INT NOT NULL, -- Fixed with a well-delimited data type.
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Friendship_PK PRIMARY KEY (RequesterId, AddresseeId), -- Composite PRIMARY KEY.
CONSTRAINT FriendshipToRequester_FK FOREIGN KEY (RequesterId)
REFERENCES UserProfile (UserId),
CONSTRAINT FriendshipToAddressee_FK FOREIGN KEY (AddresseeId)
REFERENCES UserProfile (UserId)
);
Dans cette mode:
- chaque table de base représente un type d'entité individuel;
- chaque colonne représente une propriété unique du type d'entité respectif ;
- un spécifiques type de données une est fixée pour chaque colonne afin de garantir que toutes les valeurs qu'elle contient appartiennent à un particulier et bien défini ensemble , que ce soit INT, DATETIME, CHAR, etc .; et
- plusieurs contraintes b sont configurées (de manière déclarative) afin de garantir que les assertions sous forme de lignes conservées dans toutes les tables respectent les règles métier déterminées au niveau du schéma conceptuel.
Avantages d'une colonne à valeur unique
Comme démontré, vous pouvez, par exemple:
Profitez de l' intégrité référentielle imposée par le système de gestion de base de données (SGBD pour la brièveté) pour la Friendship.AddresseeId
colonne, car la contraindre en tant que CLÉ ÉTRANGÈRE (FK pour la brièveté) qui fait référence à la UserProfile.UserId
colonne garantit que chaque valeur pointe vers une ligne existante .
Créez une CLÉ PRIMAIRE composite (PK) composée de la combinaison de colonnes (Friendship.RequesterId, Friendship.AddresseeId)
, aidant à distinguer avec élégance toutes les lignes INSÉRÉES et, naturellement, à protéger leur unicité .
Bien sûr, cela signifie que l'attachement d'une colonne supplémentaire pour les valeurs de substitution affectées par le système (par exemple, une configuration avec la propriété IDENTITY dans Microsoft SQL Server ou avec l' attribut AUTO_INCREMENT dans MySQL) et l'aide INDEX est entièrement superflue .
Limitez les valeurs retenues Friendship.AddresseeId
à un type de données précis c (qui doit correspondre, par exemple, à celui établi pour UserProfile.UserId
, dans ce cas INT), en laissant le SGBD se charger de la validation automatique pertinente .
Ce facteur peut également aider à (a) utiliser les fonctions de type intégrées correspondantes et (b) optimiser l' utilisation de l' espace disque .
Optimisez la récupération des données au niveau physique en configurant des INDEX subordonnés petits et rapides pour la Friendship.AddresseeId
colonne, car ces éléments physiques peuvent considérablement aider à accélérer les requêtes qui impliquent ladite colonne.
Certes, vous pouvez, par exemple, mettre en place un INDEX à une seule colonne pour Friendship.AddresseeId
seul, un INDEX à plusieurs colonnes qui englobe Friendship.RequesterId
et Friendship.AddresseeId
, ou les deux.
Évitez la complexité inutile introduite par la «recherche» de valeurs distinctes qui sont collectées ensemble dans la même colonne (très probablement dupliquées, mal tapées, etc.), un plan d'action qui finirait par ralentir le fonctionnement de votre système, car vous le feriez doivent recourir à des méthodes non relationnelles consommatrices de temps et de ressources pour accomplir ladite tâche.
Ainsi, il existe plusieurs raisons qui nécessitent d'analyser attentivement l'environnement commercial pertinent afin de marquer avec précision le type d de chaque colonne de tableau.
Comme expliqué, le rôle joué par le concepteur de base de données est primordial pour tirer le meilleur parti (1) des avantages de niveau logique offerts par le modèle relationnel et (2) des mécanismes physiques fournis par le SGBD de choix.
a , b , c , d Evidemment, lorsque vous travaillez avec des plates-formes SQL (par exemple, Firebird et PostgreSQL ) qui prennent en charge la création de DOMAIN (une caractéristique relationnelle distincte), vous pouvez déclarer des colonnes qui n'acceptent que des valeurs qui appartiennent à leurs respectives (convenablement contraintes et parfois DOMAINs partagés).
Un ou plusieurs programmes d'application partageant la base de données considérée
Lorsque vous devez utiliser arrays
le code du ou des programmes d'application accédant à la base de données, il vous suffit de récupérer l' intégralité du ou des jeux de données pertinents , puis de les «lier» à la structure de code concernée ou d'exécuter le processus (s) d'application associés qui devraient avoir lieu.
Autres avantages des colonnes à valeur unique: les extensions de structure de base de données sont beaucoup plus faciles
Un autre avantage du maintien du AddresseeId
point de données dans sa colonne réservée et correctement typée est qu'il facilite considérablement l'extension de la structure de la base de données, comme je le montrerai ci-dessous.
Progression du scénario: intégration du concept de statut d'amitié
Étant donné que les amitiés peuvent évoluer au fil du temps, vous devrez peut-être suivre un tel phénomène, vous devrez donc (i) étendre le schéma conceptuel et (ii) déclarer quelques tables supplémentaires dans la disposition logique. Alors, organisons les prochaines règles métier pour délimiter les nouvelles incorporations:
- Une amitié tient une-à-plusieurs FriendshipStatuses
- Un FriendshipStatus est principalement identifié par la combinaison de son RequesterId , de son AddresseeId et de son SpecifiedDateTime
- Un utilisateur spécifie zéro ou un ou plusieurs FriendshipStatuses
- Un statut classe zéro à un ou plusieurs FriendshipStatuses
- Un statut est principalement identifié par son StatusCode
- Un statut est alternativement identifié par son nom
Diagramme IDEF1X étendu
Successivement, le diagramme IDEF1X précédent peut être étendu afin d'inclure les nouveaux types d'entité et les types d'interrelation décrits ci-dessus. Un diagramme décrivant les éléments précédents associés aux nouveaux est présenté à la figure 2 :
Ajouts de structure logique
Ensuite, nous pouvons allonger la disposition DDL avec les déclarations suivantes:
--
CREATE TABLE MyStatus ( -- Denotes an independent entity type.
StatusCode CHAR(1) NOT NULL,
Name CHAR(30) NOT NULL,
--
CONSTRAINT MyStatus_PK PRIMARY KEY (StatusCode),
CONSTRAINT MyStatus_AK UNIQUE (Name) -- ALTERNATE KEY.
);
CREATE TABLE FriendshipStatus ( -- Represents an associative entity type.
RequesterId INT NOT NULL,
AddresseeId INT NOT NULL,
SpecifiedDateTime DATETIME NOT NULL,
StatusCode CHAR(1) NOT NULL,
SpecifierId INT NOT NULL,
--
CONSTRAINT FriendshipStatus_PK PRIMARY KEY (RequesterId, AddresseeId, SpecifiedDateTime), -- Composite PRIMARY KEY.
CONSTRAINT FriendshipStatusToFriendship_FK FOREIGN KEY (RequesterId, AddresseeId)
REFERENCES Friendship (RequesterId, AddresseeId), -- Composite FOREIGN KEY.
CONSTRAINT FriendshipStatusToMyStatus_FK FOREIGN KEY (StatusCode)
REFERENCES MyStatus (StatusCode),
CONSTRAINT FriendshipStatusToSpecifier_FK FOREIGN KEY (SpecifierId)
REFERENCES UserProfile (UserId)
);
Par conséquent, chaque fois que le statut d'une amitié donnée doit être mis à jour, les utilisateurs n'auront qu'à INSÉRER une nouvelle FriendshipStatus
ligne, contenant:
les valeurs appropriées RequesterId
et - AddresseeId
tirées de la ligne concernée Friendship
-;
la StatusCode
valeur nouvelle et significative - tirée de MyStatus.StatusCode
-;
l'instant INSERTion exact, c'est-à-dire SpecifiedDateTime
- en utilisant de préférence une fonction serveur afin que vous puissiez la récupérer et la conserver de manière fiable -; et
la SpecifierId
valeur qui indiquerait le respectif UserId
qui a entré le nouveau FriendshipStatus
dans le système —idéalement, à l'aide des installations de vos applications—.
Dans cette mesure, supposons que le MyStatus
tableau contient les données suivantes - avec des valeurs PK qui sont (a) compatibles avec l'utilisateur final, le programmeur d'application et DBA et (b) petites et rapides en termes d'octets au niveau de l' implémentation physique -:
+ -——————————- + -—————————- +
| StatusCode | Nom |
+ -——————————- + -—————————- +
| R | Demandé |
+ ------------ + ----------- +
| A | Accepté |
+ ------------ + ----------- +
| D | Refusée |
+ ------------ + ----------- +
| B | Bloqued |
+ ------------ + ----------- +
Ainsi, le FriendshipStatus
tableau peut contenir des données comme indiqué ci-dessous:
+ -———————————- + -———————————- + -———————————————————— ———- + -——————————- + -———————————- +
| RequesterId | AddresseeId | SpecifiedDateTime | StatusCode | SpecifierId |
+ -———————————- + -———————————- + -———————————————————— ———- + -——————————- + -———————————- +
| 1750 | 1748 | 01/04/2016 16: 58: 12.000 | R | 1750 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 2016-04-02 09: 12: 05.000 | A | 1748 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 04/04/2016 10: 57: 01.000 | B | 1750 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 07/04/2016 07: 33: 08.000 | R | 1748 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
| 1750 | 1748 | 08/04/2016 12: 12: 09.000 | A | 1750 |
+ ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
Comme vous pouvez le voir, on peut dire que le FriendshipStatus
tableau sert à constituer une série chronologique .
Postes pertinents
Vous pourriez tout aussi bien être intéressé par:
- Cette réponse dans laquelle je suggère une méthode de base pour traiter une relation plusieurs-à-plusieurs commune entre deux types d'entités dissemblables.
- Le diagramme IDEF1X illustré à la figure 1 qui illustre cette autre réponse . Portez une attention particulière aux types d'entités nommés Mariage et Descendance , car ce sont deux autres exemples de la façon de gérer le «problème d'explosion des pièces».
- Ce message qui présente une brève délibération sur la conservation de différentes informations dans une seule colonne.