Bonjour,
voici mon problème :
j'ai 2 tables , fournisseurs et clients.
comment modéliser en mcd qu'un fournisseur peut être client et donc vice versa. ?
merci
Bonjour,
voici mon problème :
j'ai 2 tables , fournisseurs et clients.
comment modéliser en mcd qu'un fournisseur peut être client et donc vice versa. ?
merci
bonjour,
il faudrait ajouter une troisième table "personne".
-> dans la table personne, on peut préciser les champs "numero", "nom", "prenom", "adresse", etc...
-> dans la table fournisseur, on peut préciser les champs propres au fournisseur + le champ "numero" de la table personne en clé étrangère
-> dans la table client, on peut préciser les champs propres au client + le champ "numero" de la table personne en clé étrangère.
la relation entre ces tables est la suivante :
personne (0.n) - (0.1) fournisseur
(car une personne peut être n fois fournisseur, un fournisseur correspond à 1 et 1 seule personne).
personne (0.n) - (0.1) client
(car une personne peut être n fois client, un client correspond à 1 et 1 seule personne).
en espérant avoir répondu à la question...
delaio.
Bonsoir,
Mettre en œuvre une entité-type Personne est une bonne chose, et signifie que l’on définit une relation d’héritage entre Personne et Client d’une part, Personne et Fournisseur d’autre part, une personne pouvant être à la fois client et fournisseur :
![]()
MLD correspondant :
![]()
Toutefois, une personne peut être un client et un client est exactement une personne, donc en termes de cardinalités, ça n’est pas du 0,N - 0,1, mais 0,1 - 1,1. Au niveau MLD, PesonneId est clé primaire pour la table Personne et à la fois clé primaire et clé étrangère pour la table Client.
Principe identique pour les fournisseurs.
Bien entendu, les sous-types Client et Fournisseur peuvent être dotés d'identifiants supplémentaires tels que NoClient et NoFournisseur.
Bonjour,
Donc si j'ai une entité commande_client et etant donnée qu'un fournisseur peut-être client et vice-versa alors au lieu de mettre l'attribut IdClient dans l'entité commande_client on mettra l'attribut PersonneId ?
Bonjour,
Si l’on prend en compte les commandes des clients, le MCD devient le suivant :
![]()
Vous aurez noté l’utilisation de l’identification relative (cardinalité 1,1 mise entre parenthèses)
Et le MLD :
![]()
SQL :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 Create Table Personne ( PersonneId Int Not null, PersonneSiret Varchar(24) Not null, PersonneNom Varchar(48) Not null, PersonneAdresse Varchar(48) Not null, Constraint Personne_PK Primary Key (PersonneId), Constraint Personne_AK Unique (PersonneSiret) ) ; Create Table Fournisseur ( PersonneId Int Not null, TauxRemise Int Not null, Constraint Fournisseur_PK Primary Key (PersonneId), Constraint Fournisseur_Personne_1 Foreign Key (PersonneId) References Personne (PersonneId) ) ; Create Table Client ( PersonneId Int Not null, ConditionsTarifaires Varchar(48) Not null, Constraint Client_PK Primary Key (PersonneId), Constraint Client_Personne_C1 Foreign Key (PersonneId) References Personne (PersonneId) ) ; Create Table Commande ( PersonneId Int Not null, CdeIdRelatif Int Not null, CdeMumero Char(12) Not null, CdeDate DateTime Not null, Constraint Commande_PK Primary Key (PersonneId, CdeIdRelatif), Constraint CCommande_AK Unique (CdeMumero), Constraint Commande_Client_C1 Foreign Key (PersonneId) References Client (PersonneId) );
Exemple sous forme de tableau :
Vous noterez l’absence d’un attribut nommé IdClient, car il ferait double emploi avec l’attribut PersonneId. Cela dit, rien ne vous empêche de renommer PersonneId en IdClient dans les tables Client et Commande.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 Personne {PersonneId PersonneSiret PersonneNom PersonneAdresse} p1 Sir1 Nom1 Adr1 p2 Sir2 Nom2 Adr2 p3 Sir3 Nom3 Adr3 Fournisseur {PersonneId TauxRemise} p2 tau1 p3 tau3 Client {PersonneId ConditionsTarifaires} p1 cond1 p3 cond3 Commande {PersonneId CdeIdRelatif CdeNumero CdeDate} p1 1 n1 d1 p1 2 n2 d2 p1 3 n3 d3 p3 1 n4 d4 p3 2 n5 d5
A noter encore que l’attribut CdeNumero de la table Commande (c'est à dire le numéro connu de l'utilisateur) est clé candidate au même titre que la paire {PersonneId, CdeIdRelatif} cachée à l'utilisateur. De même, l’attribut PersonneSiret est clé candidate de la table Personne.
on pourrait même eclater l'entité personne en deux, une identifiant la personne et l'autre ces adresses :
1) personne_identite avec comme attributs :
(PersonneId, PersonneSiret, PersonneNom,....)
2) personne_adresse avec comme attributs :
(Adresse_Id, PersonneId, Adresse_Type, Adresse_Ligne1,Adresse_Ligne2,.....)
l'attribut Adresse_Type aura pour valeur [LIV,FACT,PER)
LIV=adresse de livraison, FACT=adresse de facturation,
PER = personnel dans le cas d'un salarié par exemple.
alors je ne sais pas si il y a mieux.
Je me demande aussi si on ne peut pas mettre les entités commande client et fournisseur dans une seule du fait que pratiquement les attributs des deux entités peuvent être identiques (date, montant_ht, montant_tva, montant_ttc, etc....) à l'exception peut-être du numero de commande.....?
Bonsoir,
Tout dépend des règles de gestion, à savoir si l’on gère une seule ou plusieurs adresses, mais allons-y, ça peut rendre service. Dans une entreprise, il est un fait que de façon générale, on doit gérer les adresses de livraison, de facturation, etc. Autrement dit, une personne peut avoir plus d’une adresse, mais la modélisation que vous proposez est à aménager, si on retient l’hypothèse qu’une personne a une seule adresse de facturation, une seule adresse de livraison, etc.
1) Au niveau conceptuel, une adresse est une propriété de la personne, que cette propriété soit mono ou multivaluée. Sémantiquement parlant, cela se traduit (en Merise) par une identification relative (cardinalité 1,1 mise entre parenthèses), c'est-à-dire par une entité-type faible dans le modèle Entité/Relation de Chen, une caractéristique dans le modèle RM/T de Codd, une composition dans un diagramme de classes, etc. :
![]()
2) au niveau logique :
![]()
Au niveau SQL :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 Create Table Adresse ( PersonneId Int Not null , AdresseType Char(4) Not null , Adresse_Ligne_1 Varchar(48) Not null , Adresse_Ligne_2 Varchar(48) Not null , Etc Varchar(48) Not null , Constraint Adresse_PK Primary Key (PersonneId, AdresseType) , Constraint Adresse_Personne_C1 Foreign Key (PersonneId) References Personne (PersonneId) , Constraint Adresse_Personne_C2 Check (AdresseType IN ('livr', 'fact', 'pers'))) ;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 Personne {PersonneId PersonneSiret PersonneNom PersonneAdresse} p1 Sir1 Nom1 Adr1 p2 Sir2 Nom2 Adr2 p3 Sir3 Nom3 Adr3 Adresse {PersonneId AdresseType Adresse_Ligne_1 Adresse_Ligne_2 Etc.} p1 livr Martin Lille 2, rue Freud ... p1 fact Martin Groupe. 1, av. Sigmund ... p1 pers P. Martineau 8, rue Freud ... p2 pers Superkiller S.A. 12, rue des Lilas ... p3 livr DVP 130 rue Dupont ... p3 fact DVP 130 rue Dupont ...
Mais si une personne peut avoir plusieurs adresses de livraison, de facturation, etc., alors c’est votre solution qui est à retenir :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 Adresse {PersonneId AdresseId AdresseType Adresse_Ligne_1 Adresse_Ligne_2 Etc.} p1 1 livr Martin Lille 2, rue Freud ... p1 2 fact Martin Groupe. 1, av. Sigmund ... p1 3 pers P. Martineau 8, rue Freud ... p1 4 livr A. Colineau 1, rue Tintin ... p2 1 pers Superkiller S.A. 12, rue des Lilas ... p3 1 livr DVP 130 rue Dupont ... p3 2 fact DVP 130 rue Dupont ...
On peut envisager que l’entité-type Commande soit une propriété multivaluée de l’entité-type Personne (entité-type faible), spécialisée à son tour en CommandeClient (en relation avec l’entité-type Client) et CommandeFournisseur (en relation avec Fournisseur), techniquement ça ne pose pas de problème particulier, mais c’est à discuter avec le chef de projet.
Ce modèle suppose que tous les clients sont des personnes. Dans certaines entreprises, un client peut être une autre entreprise ou une personne.
Un fournisseur est par contre dans l'extrème majorité des cas une entreprise, fut-elle une entreprise individuelle !
Comment alors distinguer, à partir de la commande, si le client est une entreprise ou une personne ?
Personne -0,1----Etre----(0,1)- Client -0,n----Passer----(1,1)- Commande
Entreprise -0,1----Etre----(0,1)-----|
|
|----------------0,1----Etre----(1,1)----Fournisseur
N'est-il alors pas nécessaire de typer le client (personne ou entreprise) ?
D'ailleurs je devrais plutôt employer le terme "Organisme" (terme, si je me souviens bien, employé dans la famille de normes ISO 9000) plutôt que "Entreprise" parce qu'une administration, une association, une fondation... peuvent aussi être client, voire fournisseur.
Je le pense. Par exemple :
![]()
MLD correspondant :
N.B. « Personne » représente ici un terme général, informel (il peut y avoir des personnes morales outre des personnes physiques). Dans la réalité des projets, le sens précis des entités-types est fourni dans un dossier de conception et chaque chef de projet définit et utilise les termes qu’il estime pertinents et conformes aux us et coutumes des utilisateurs.
Es-ce que ce n'est pas un peu emcombrant d'avoir 2 entités (ClientAvecSiret, ClientSansSiret) au lieu d'avoir dans l'entité Client un attribut type_client et eventuellement les deux attribut ClientSiret, ConditionTarifaire evidemment il y aura des nulls lorsque le type_client n'est pas une entrepise mais bon.... c'est juste pour eviter d'avoir des tables en plus.
Par ailleurs, avec ce schéma hierarchique qui commence avec l'entité Personne qui peut recevoir des client, fournisseur, salarié et distinctement et chacun identifié par une clé unique. Avec cette logique, ne serait-il pas hasardeux de fusionner les entités :
1) commande client et commande fournisseur
2) facture client et facture fournisseur
3) reglement client et reglement fournisseur
et dans la mesure oû les entités client et fournisseur ont pratiquement les mêmes attributs ? avec une legere difference de quelque champs ( un à deux) qui distingue le client du fournisseur ?
N'etant pas trés merisien je peux me tromper parce que cela parait grossier cette idée de fusion......![]()
Le nombre d’entités-types dans un modèle n’a pas à être pris en compte quand on modélise. Quant à réintégrer les sous-types dans le surtype, cela revient à faire de la salade sémantique. Au niveau des opérations vous aurez à vous battre contre le bonhomme NULL et aurez à développer des requêtes plus complexes dès lors que vous traiterez d’une population donnée (par exemple les clients à Siret). N’oubliez pas que par le mécanisme des vues, vous pourrez définir des tables virtuelles basées sur la jointure des surtypes et types.
Créons par exemple les tables SQL (SGBD SQL Server) :
Créons la vue et les triggers de mise à jour des fournisseurs :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 CREATE TABLE Personne ( PersonneId Int NOT NULL, PersonneNom Varchar(48) NOT NULL, CONSTRAINT Personne_PK PRIMARY KEY (PersonneId), ) ; CREATE TABLE Fournisseur ( PersonneId Int NOT NULL, FournisseurSiret Varchar(24) NOT NULL, TauxRemise Int NOT NULL, CONSTRAINT Fournisseur_PK PRIMARY KEY (PersonneId), CONSTRAINT Fournisseur_AK UNIQUE (FournisseurSiret), CONSTRAINT Fournisseur_Personne_FK FOREIGN KEY (PersonneId) REFERENCES Personne (PersonneId) ON DELETE CASCADE ) ; CREATE TABLE Client ( PersonneId Int NOT NULL, CONSTRAINT Client_PK PRIMARY KEY (PersonneId), CONSTRAINT Client_Personne_FK FOREIGN KEY (PersonneId) REFERENCES Personne (PersonneId) ON DELETE CASCADE ) ; CREATE TABLE ClientAvecSiret ( PersonneId Int NOT NULL, ClientSiret Varchar(24) NOT NULL, ConditionsTarifaires Varchar(48) NOT NULL, CONSTRAINT ClientAvecSiret_PK PRIMARY KEY (PersonneId), CONSTRAINT ClientAvecSiret_AK UNIQUE (ClientSiret), CONSTRAINT ClientAvecSiret_Client_FK FOREIGN KEY (PersonneId) REFERENCES Client (PersonneId) ON DELETE CASCADE ) ; CREATE TABLE ClientSansSiret ( PersonneId Int NOT NULL, PersonneNo Varchar(24) NOT NULL, CONSTRAINT ClientSansSiret_PK PRIMARY KEY (PersonneId), CONSTRAINT ClientSansSiret_AK UNIQUE (PersonneNo), CONSTRAINT ClientSansSiret_Client_FK FOREIGN KEY (PersonneId) REFERENCES Client (PersonneId) ON DELETE CASCADE ) ; CREATE TABLE Commande ( PersonneId Int NOT NULL, CdeIdRelatif Int NOT NULL, CdeMumero Char(12) NOT NULL, CdeDate DateTime NOT NULL, CONSTRAINT Commande_PK PRIMARY KEY (PersonneId, CdeIdRelatif), CONSTRAINT Commande_AK UNIQUE (CdeMumero), CONSTRAINT Commande_Client_FK FOREIGN KEY (PersonneId) REFERENCES Client (PersonneId) On Delete No Action ) ; CREATE TABLE Adresse ( PersonneId Int NOT NULL , AdresseType Char(4) NOT NULL , Adresse_Ligne_1 Varchar(48) NOT NULL , Adresse_Ligne_2 Varchar(48) NOT NULL , Etc Varchar(48) NOT NULL , CONSTRAINT Adresse_PK PRIMARY KEY (PersonneId, AdresseType) , CONSTRAINT Adresse_Personne_FK FOREIGN KEY (PersonneId) REFERENCES Personne (PersonneId) ON DELETE CASCADE , CONSTRAINT Adresse_Personne_C2 CHECK (AdresseType IN ('livr', 'fact', 'pers')) ) ;
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 CREATE VIEW Fournisseur_V (PersonneId, PersonneNom, FournisseurSiret, TauxRemise) AS SELECT x.PersonneId, x.PersonneNom, y.FournisseurSiret, y.TauxRemise FROM Personne AS x JOIN Fournisseur y ON x.PersonneId = y.PersonneId GO CREATE TRIGGER Fournisseur_INSERT ON Fournisseur_V INSTEAD OF INSERT AS INSERT INTO Personne SELECT PersonneId, PersonneNom FROM INSERTED ; INSERT INTO Fournisseur SELECT PersonneId, FournisseurSiret, TauxRemise FROM INSERTED ; GO CREATE TRIGGER Fournisseur_DELETE ON Fournisseur_V INSTEAD OF DELETE AS DELETE FROM Personne WHERE EXISTS (SELECT * FROM DELETED WHERE Personne.PersonneId = DELETED.PersonneId) ; GO CREATE TRIGGER Fournisseur_UPDATE ON Fournisseur_V INSTEAD OF UPDATE AS IF UPDATE (PersonneId) BEGIN RAISERROR ('On ne touche pas aux clés primaires !', 16, 1) ROLLBACK TRAN RETURN END IF UPDATE(PersonneNom) UPDATE Personne SET PersonneNom = (SELECT DISTINCT PersonneNom FROM INSERTED) WHERE EXISTS (SELECT DELETED.PersonneNom FROM DELETED WHERE DELETED.PersonneId = Personne.PersonneId) IF UPDATE(FournisseurSiret) OR UPDATE(TauxRemise) UPDATE Fournisseur SET FournisseurSiret = (SELECT DISTINCT FournisseurSiret FROM INSERTED) , TauxRemise = (SELECT DISTINCT TauxRemise FROM INSERTED) WHERE EXISTS (SELECT DELETED.FournisseurSiret FROM DELETED WHERE DELETED.PersonneId = Fournisseur.PersonneId) OR EXISTS (SELECT DELETED.TauxRemise FROM DELETED WHERE DELETED.PersonneId = Fournisseur.PersonneId) ;
Pour accéder aux données d’un fournisseur, inutile de se poser des questions sur le type de la personne :
même chose pour les clients.
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT * FROM Fournisseur_V WHERE PersonneNom = 'Alain' ;
Pour créer un fournisseur on se sert de la vue (le SGBD se charge de ventiler dans les tables de base) :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part INSERT INTO Fournisseur_V VALUES (1, 'psn 1', 'siret 1', 10) ;
Pour modifier les données d'un fournisseur, même principe :
Et pour supprimer :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 UPDATE Fournisseur_V SET PersonneNom = 'toto' , FournisseurSiret ='siret 2' ;
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part DELETE FROM Fournisseur_V where FournisseurSiret ='siret 2' ;
Vous pouvez aussi méditer la discussion avec Heledir.
Cf. la réponse précédente. La salade sémantique n’est pas recommandable. Ça n’est pas pour rien qu’il faut applaudir celui qui a proposé le premier le concept d’héritage pour la modélisation des données. Peut-être la famille Smith ? (Cf. “Database Abstractions: Aggregation and Generalization”, 1977).
Bonjour,
Je viens de consulter le topic et il est assez charger je réserverais cela pour la soirée l'esprit sera assez disponible...Vous pouvez aussi méditer la discussion avec Heledir.
Merci fsmrel
hep !! c'est un gros morceau cette discussion avec Heledir.
c'est un dialogue socratique cette discussion ?
pardon ..... dialogue dialectiquement merisien ? Il y a du fond et du mouvement ....
En tous cas la version imprimable m'a faite 37 pages sans compter les diagrammes........ es-ce un tutoriel, un guide pratique de la pensée merisienne ? J'en aurais pour une bonne semaine.
Un grand salut chinois à fsmrel et Heledir![]()
Une modeste tentative en ce sens...
Heledir est demandeur et ne se décourage pas. Je pense que parti du niveau débutant il a acquis des connaissances utiles (le concept d'héritage, le passage au niveau logique, le métabolisme des données au-delà de leur anatomie, etc.) On a pas mal balayé et déblayé...
Réduisez sensiblement la taille de la police de caractères et la taille des diagrammes ?
Puis, si vous avez des questions hélediriennes, n’hésitez pas...
Merci, et bonne lecture.
Bonjour,
Je reviens sur cette discussion, fort intéressante et déjà ancienne, car j'ai besoin d'ajouter de la complexité au modèle.
Je suis loin d'être une experte, ce qui m'amène à solliciter votre expertise, FSMREL.
Alors voici mon problème :
Dans la réalité un "Organisme" possédant un numéro de SIREN peut comporter plusieurs Etablissements partageant donc le même numéro de SIREN mais disposant chacun d'un numéro SIRET spécifique. Par ailleurs, le numéro de SIRET détermine l'adresse, chaque établissement ayant son adresse propre.
Que devient donc le modèle, sachant que bien évidemment j'ai les mêmes contraintes :
- "Un client peut être fournisseur",
- Fournisseurs/Clients peuvent ne pas avoir de N° SIREN
- Eviter les NULL
Bien cordialement.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager