Bonsoir Seb,

Envoyé par
seb_perl
Pourquoi ne pas propager juste ModeleId ?
Considérons l’exemple tabulaire qui suit :
Marque
1 2 3 4 5
| MarqueId MarqueNom
--------
1 Renault
2 Peugeot
3 Citroen |
Modele
1 2 3 4 5 6 7 8
| MarqueId ModeleId ModeleNom
-------- --------
1 1 Clio Nouvelle
1 2 R5 d'époque
2 1 302 super
2 2 403 prestige
3 1 DS19 de luxe
3 2 2CV de compète |
Motorisation
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| MarqueId ModeleId MotorisationId Motorisation CO2
-------- -------- --------------
1 1 1 motor a 1
1 1 2 motor b 5
1 2 1 motor c 3
1 2 2 motor d 1
2 1 1 motor e 2
2 1 2 motor f 6
2 2 1 motor g 4
2 2 2 motor h 1
3 1 1 motor i 3
3 1 2 motor j 5
3 2 1 motor k 1
3 2 2 motor l 1 |
Finition
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| MarqueId ModeleId FinitionId Finition
-------- -------- ----------
1 1 1 fini a
1 1 2 fini b
1 2 1 fini c
1 2 2 fini d
2 1 1 fini e
2 1 2 fini f
2 2 1 fini g
2 2 2 fini h
3 1 1 fini i
3 1 2 fini j
3 2 1 fini k
3 2 2 fini l |
Offre
1 2 3 4 5 6 7
| MarqueId ModeleId OffreId MotorisationId FinitionId Prix NbPortes
-------- -------- ------- --------------
1 1 1 1 1 10000 3
1 1 2 1 1 11000 5
1 1 3 2 1 15000 3
2 1 1 1 2 6000 5
... ... ... ... ... ... ... |
Concernant la table Modele, vous noterez que pour la marque Renault (MarqueId = 1), l’attribut ModeleId prend les valeurs successives 1, 2, etc., même chose pour les autres marques. Ceci vaut pour les tables Motorisation, Finition et Offre.
Situons-nous maintenant sur un plan conceptuel.
Quand je parle d’identification relative, par exemple identifier Modele relativement à Marque, je considère qu’au niveau conceptuel, Modele est une entité-type « faible » par rapport à Marque qui est une entité-type « forte » : la suppression d’une marque entraîne la suppression de ses modèles, car ceux-ci n’ont de sens ontologique qu’au travers d’une marque. Quand vous pensez « Clio », vous pensez « Renault ». Inversement, si vous supprimez un modèle, vous ne supprimez pas la marque. On peut encore dire que l’entité-type Modele est en réalité une propriété multivaluée de l’entité-type Marque (que je renomme ci-dessous MarqueGr) : du point de vue de la théorie relationnelle, la variable relationnelle Modele peut faire l’objet d’un attribut de type RELATION (table en SQL) :
MarqueGr {MarqueId INTEGER, MarqueNom CHAR, Modele RELATION {ModeleId INTEGER, ModeleNom CHAR}}
Ceci dit, il est d’usage se sortir les attributs de type RELATION et d’en faire des variables relationnelles comme les autres, à l’aide d’un opérateur relationnel appelé UNGROUP (dont le symétrique s’appelle GROUP). On peut ainsi produire des variables relationnelles dont la structure est plus familière et correspondent à la représentation tabulaire obtenue avec Workbench :
Marque {MarqueId INTEGER, MarqueNom CHAR}
Modele {MarqueId INTEGER, ModeleId INTEGER, ModeleNom CHAR}
Traduction au niveau SQL :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| CREATE TABLE Marque
(
MarqueId INT NOT NULL ,
MarqueNom VARCHAR(45) NOT NULL ,
PRIMARY KEY (MarqueId)
) ;
CREATE TABLE Modele
(
MarqueId INT NOT NULL ,
ModeleId INT NOT NULL ,
ModeleNom VARCHAR(45) NOT NULL ,
PRIMARY KEY (MarqueId, ModeleId) ,
CONSTRAINT Modele_Marque_fk
FOREIGN KEY (MarqueId) REFERENCES Marque (MarqueId)
) ; |
Vous noterez que l’attribut MarqueId entre dans la composition de la clé primaire de Modele, mais aussi dans la composition de la clé étrangère permettant de référencer la table Marque.
Vous pouvez tout à fait propager ModeleId seul, c'est-à-dire ne pas utiliser l’identification relative à Marque :
Ce qui donne en SQL :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| CREATE TABLE Marque
(
MarqueId INT NOT NULL ,
MarqueNom VARCHAR(45) NOT NULL ,
PRIMARY KEY (MarqueId)
) ;
CREATE TABLE Modele
(
MarqueId INT NOT NULL ,
ModeleId INT NOT NULL ,
ModeleNom VARCHAR(45) NOT NULL ,
PRIMARY KEY (ModeleId) ,
CONSTRAINT Modele_Marque_fk
FOREIGN KEY (MarqueId) REFERENCES Marque (MarqueId)
) ; |
Seule la composition de la clé primaire de la table Modele a changé.
Personnellement, je préfère conserver l’identification relative entre Marque et Modele, car :
1) Au niveau conceptuel, d’un point de vue sémantique, ontologique, on perçoit parfaitement les choses ;
2) Au niveau logique (disons Workbench) puis SQL, on peut ainsi améliorer certaines requêtes, du genre :
Quel est le prix moyen d’une offre par marque ?
Requête que l’on code ainsi (une seule jointure) :
1 2 3 4
| SELECT a.MarqueNom, AVG(b.prix) AS PrixMoyen
FROM Marque AS a
JOIN Offre AS b ON a.MarqueId = b.MarqueId
GROUP BY b.MarqueId, a.MarqueNom ; |
Alors qu’en n’identifiant que relativement au modèle, on doit coder (une jointure supplémentaire) :
1 2 3 4 5
| SELECT a.MarqueNom, AVG(c.prix) AS PrixMoyen
FROM Marque AS a
JOIN Modele AS b ON a.MarqueId = b.MarqueId
JOIN Offre AS c ON b.ModeleId = c.ModeleId
GROUP BY b.MarqueId, a.MarqueNom ; |
Vous me direz qu’une jointure de plus, ça n’est pas dramatique : cependant, quand vous avez des tables comportant cent millions de lignes, l’économie n’est pas mince. Et puis, le nombre de tables intermédiaires entre une table « racine » telle que Marque et une table « feuille » telle que Offre peut être plus conséquent. Je vous renvoie à ce sujet au message suivant, qui traite de commandes et de livraisons par camion :
http://www.developpez.net/forums/d62...s/#post4843686 3) Au niveau physique, on joue essentiellement sur les performances. A ce sujet, je vous renvoie au message dont je viens de faire mention.

Envoyé par
seb_perl
faut propager ça à la main ou le définir en tant que relation ?
Supposons que nous conservions MarqueId comme identifiant générique, à propager jusqu’à Offre.
La clé primaire de Modèle est donc définie par le couple {MarqueId, ModeleId}, ce qui signifie que, pour établir une relation entre Marque et Modele, il suffit d’utiliser l’icône proposée par Workbench :
Place a new 1:n Identifying Relationship
Le principe est le même concernant Motorisation relativement à Modele, pour obtenir une clé primaire qui soit le triplet {MarqueId, ModeleId, MotorisationId} ; idem pour Finition.
Offre est identifiée relativement à Modèle, mais pas à Motorisation et Finition. J’aurais pu identifier relativement soit à Motorisation, soit à Finition, mais pas au deux en même temps, car la clé primaire aurait été une surclé réductible (présence d’attributs dangereusement superflus) : ne faisons donc pas de jaloux Quoi qu’il en soit, j’ai utilisé l’icône
Place a new 1:n Non-Identifying Relationship
entre Motorisation et Offre d’une part, puis Finition et Offre d’autre part.
Au résultat, Offre a l’allure suivante qui n’est pas satisfaisante :
Il y a donc quelques actions à réaliser pour retrouver le MLD que je vous avais proposé dans mon précédent message :
1) Intégrer les attributs MarqueId et ModeleId à la clé primaire

=>
2) La relation entre Offre et Motorisation convient :
Par contre, la relation entre Offre et Motorisation n’est pas satisfaisante, car les attributs MarqueId1 et ModeleId1 sont inutiles :
On modifie donc en conséquence la composition de la clé étrangère Offre_Finition_Fk :
3) Les attributs MarqueId1 et ModeleId1 ne jouent plus de rôle particulier :
On peut donc les supprimer et l’on retrouve le MLD attendu :
Partager