Ave,
Comment mettre en oeuvre une contrainte imposant le respect des cardinalités 1,n définies dans un MCD ?
Je reviens sur les conclusions que l’on a pu tirer à partir d’une discussion antérieure traitant de ce sujet.
Avec SQL : sans insert dans une vue, sans trigger, sans bricolage, pas de salut, d’autant plus qu’Hilarion traîne en permanence ses guêtres pour ficher la zoubia. Les débats dans cette discussion furent animés, les baroudeurs s'y étaient mis (Paprick, escartefigue, CinePhil, SQLpro...)![]()
Voyons comment les choses se passent dan le cadre du Modèle Relationnel de Données, c’est-à-dire avec Tutorial D.
Prenons le cas des devis proposé par Patrick dans le post #46 de cette discussion (de plus de 70 échanges...) :
Le LDD SQL :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 CREATE TABLE Produit (RefProduit INT, Designation VARCHAR(50) NOT NULL, Prix INT NOT NULL, CONSTRAINT Produit_PK PRIMARY KEY (RefProduit)) ; CREATE TABLE Devis (NumDevis INT, DateDevis DATE NOT NULL, CONSTRAINT Devis_PK PRIMARY KEY (NumDevis)) ; CREATE TABLE LigneDevis (NumDevis INT, RefProduit INT, Quantite INT NOT NULL, CONSTRAINT LigneDevis_PK PRIMARY KEY (NumDevis, RefProduit), CONSTRAINT LigneDevisProduit_FK FOREIGN KEY (RefProduit) REFERENCES Produit, CONSTRAINT LigneDevisDevis_FK FOREIGN KEY (NumDevis) REFERENCES Devis ON DELETE CASCADE) ;
Le LDD façon Tutorial D :
Code Tutorial D : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 VAR Produit BASE RELATION {RefProduit INT, Designation CHAR, Prix INT} KEY {RefProduit} ; VAR Devis BASE RELATION {NumDevis INT, DateDevis CHAR} KEY {NumDevis} ; VAR LigneDevis BASE RELATION {NumDevis INT, RefProduit CHAR, Quantite INT} KEY {NumDevis, RefProduit} ;
La contrainte imposant la cardinalité 1,n requise par le MCD :
Code Tutorial D : Sélectionner tout - Visualiser dans une fenêtre à part CONSTRAINT CDL Devis {NumDevis} = LigneDevis {NumDevis} ;
Il s’agit d’une contrainte d’égalité faisant qu’un devis ne peut exister sans ligne de devis et qu’une ligne de devis ne peut exister sans devis. CDL est le nom de la contrainte, "Devis {NumDevis}" est la projection de Devis sur l’attribut NumDevis et "LigneDevis {NumDevis}" la projection de LigneDevis sur l’attribut NumDevis.
Il est inutile de doter LigneDevis d’une clé étrangère référençant Devis : la contrainte CDL fait office. Toutefois, une contrainte d’intégrité référentielle (nommée CLP ci-dessous) est nécessaire pour s’assurer qu’une ligne de devis référence un produit existant :
Code Tutorial D : Sélectionner tout - Visualiser dans une fenêtre à part CONSTRAINT CLP LigneDevis {RefProduit} ⊆ Produit {RefProduit} ;
Testons ça avec un jeu d’essai.
Création de produits :
Code Tutorial D : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 INSERT Produit RELATION { TUPLE {RefProduit 1, Designation "boulons de 8", Prix 100} , TUPLE {RefProduit 2, Designation "écrous", Prix 200} } ;
Tentons la création d’un devis :
Code Tutorial D : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 INSERT Devis RELATION {TUPLE {NumDevis 1, DateDevis "d01"}} ;
En l’absence d’une ligne de devis, il est évident que la contrainte CDL mettra en échec cette tentative...
Comme l’écrivait l’autre, que faire ? il est temps de parler de l’affectation multiple. Considérons l’instruction suivante :
Code Tutorial D : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 INSERT Devis RELATION { TUPLE {NumDevis 1, DateDevis "d01"} } , INSERT LigneDevis RELATION { TUPLE {NumDevis 1, RefProduit 1, Quantite 100} , TUPLE {NumDevis 1, RefProduit 2, Quantite 150} } ;
On a deux affectations (par INSERT), la 1re portant sur Devis et la 2e portant sur LigneDevis.
Mais étant séparées par une virgule (que je fais rougeoyer), ces deux affectations, font partie d’une seule instruction, elle-même bornée par un point-virgule.
Ainsi, une instruction peut comporter un nombre quelconque d’affectations et elle est à considérer comme sémantiquement atomique (tout ou rien). Autrement dit, le système traite chaque affectation, disons séquentiellement, sans aucun contrôle (autre que syntaxique), jusqu’à ce que soit atteint le point-virgule marquant la fin de l’instruction. C’est seulement à ce moment-là que les contrôles d’intégrité de la base de données sont déclenchés pour vérification de la validité du résultat de cette instruction (immediate checking), et si l’intégrité de la base de données est violée, les effets l’affectant sont annulés et un message d’erreur est émis.
=> Bref, grâce à l’affectation multiple, le respect d’une contrainte telle que CDL ne pose aucun problème, et combien d’autres contraintes en seraient bénéficiaires ! !
Pour sa part, SQL méconnaît l’affectation multiple et c’est fort dommage.
Qu’il évolue ! que de simplifications en attendre, combien de triggers bons pour la poubelle !
A propos de la suppression des devis
Grâce à l’option CASCADE attachée à la clé étrangère LigneDevisDevis_FK définie plus haut, SQL permet que la suppression d’un devis entraîne la suppression des lignes de ce devis.
Avec Tutorial D, si on veut par exemple supprimer le devis 1 et ses lignes, on utilisera l’affectation multiple :
Code Tutorial D : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 DELETE Devis WHERE NumDevis = 1 , DELETE LigneDevis WHERE NumDevis = 1 ;
A suivre...
Partager