35
Département de génie logiciel et des TI LOG660 - Bases de données de haute performance La gestion des contraintes Hiver 2011 C. Desrosiers

Contrainte d'intégrité dynamique

  • Upload
    ngoque

  • View
    225

  • Download
    0

Embed Size (px)

Citation preview

Département de génie logiciel et des TI

LOG660 - Bases de données de haute performance

La gestion des contraintes

Hiver 2011 C. Desrosiers

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 2

Gestion des contraintes d’intégrité en SQL

  Contrainte d'intégrité statique

–  respectée pour chacun des états de la BD

–  mécanismes déclaratifs

  PRIMARY KEY, UNIQUE, NOT NULL, DOMAIN, FOREIGN KEY, CHECK, ASSERTION

–  procédural

  TRIGGER (SQL:1999)

  Contrainte d'intégrité dynamique

–  contrainte sur changements d'états

–  référence aux états successifs

–  TRIGGER, REFERENCES ON DELETE…, ON UPDATE ...

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 3

Contrainte de domaine

 Types SQL –  INTEGER –  CHAR –  ...

 NOT NULL  CHECK  CREATE DOMAIN

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 4

Contrainte NOT NULL

 Par défaut : NULL

CREATE TABLE Client(noCLIENT INTEGER NOT NULL, nomClient VARCHAR(15) NOT NULL, noTéléphone VARCHAR(15) NOT NULL)

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 5

Contrainte CHECK sur une colonne

  Le noClient est supérieur à 0 et inférieur à 100,000 CREATE TABLE Client(noCLIENT INTEGER NOT NULL CHECK(noClient >0 AND noClient < 100000), nomClient VARCHAR(15) NOT NULL, noTéléphone VARCHAR(15) NOT NULL)

CREATE TABLE Client(noCLIENT INTEGER NOT NULL, nomClient VARCHAR(15) NOT NULL, noTéléphone VARCHAR(15) NOT NULL,CHECK(noClient >0 AND noClient < 100000))

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 6

Contrainte d'intégrité référentielle (FOREIGN KEY REFERENCES)

 Le noClient de la table Commande fait référence à la clé primaire noClient de la table Client

 La table Client doit d ’abord être créée –  privilège REFERENCES sur Client

 PRIMARY KEY ou UNIQUE

CREATE TABLE Commande(noCommande INTEGER NOT NULL, dateCommande DATE NOT NULL, noClient INTEGER NOT NULL, PRIMARY KEY (noCommande), FOREIGN KEY (noClient) REFERENCES Client(noClient))

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 7

Politique de gestion de la contrainte d'intégrité référentielle

  Tentative de mise à jour de la clé primaire

  Options –  NO ACTION –  CASCADE –  SET NULL –  SET DEFAULT

CREATE TABLE Commande(noCommande INTEGER NOT NULL, dateCommande DATE NOT NULL, noClient INTEGER NOT NULL, PRIMARY KEY (noCommande), FOREIGN KEY (noClient) REFERENCES Client(noClient))

DELETE FROM Client WHERE noClient = 10

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 8

Politique NO ACTION

 Rejet d ’une violation de la contrainte  Clause de défaut

Table Com m and enoCommande dateCommande noClient1 01/06/2000 102 02/06/2000 203 02/06/2000 104 05/07/2000 105 09/07/2000 306 09/07/2000 207 15/07/2000 408 15/07/2000 40

CREATE TABLE Commande(noCommande INTEGER NOT NULL, dateCommande DATE NOT NULL, noClient INTEGER NOT NULL, PRIMARY KEY (noCommande), FOREIGN KEY (noClient) REFERENCES Client ON DELETE NO ACTION)

DELETE FROM Client WHERE noClient = 10 {Opération rejetée}

DELETE FROM Client WHERE noClient = 70 {Opération acceptée}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 9

Cas du UPDATE

CREATE TABLE Commande(noCommande INTEGER NOT NULL, dateCommande DATE NOT NULL, noClient INTEGER NOT NULL, PRIMARY KEY (noCommande), FOREIGN KEY (noClient) REFERENCES Client ON UPDATE NO ACTION)

Table Com m and enoCommande dateCommande noClient1 01/06/2000 102 02/06/2000 203 02/06/2000 104 05/07/2000 105 09/07/2000 306 09/07/2000 207 15/07/2000 408 15/07/2000 40

UPDATE ClientSET noClient = 100 WHERE noCLient = 10 {Opération rejetée}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 10

Politique CASCADE

 Modification en cascade CREATE TABLE Commande(noCommande INTEGER NOT NULL, dateCommande DATE NOT NULL, noClient INTEGER NOT NULL, PRIMARY KEY (noCommande), FOREIGN KEY (noClient) REFERENCES Client ON DELETE CASCADE)

DELETE FROM Client WHERE noClient = 10{Opération acceptée temporairement}

DELETE FROM Commande WHERE noClient = 10{Opération déclenchée automatiquement}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 11

ON UPDATE CASCADE

CREATE TABLE Commande(noCommande INTEGER NOT NULL, dateCommande DATE NOT NULL, noClient INTEGER NOT NULL, PRIMARY KEY (noCommande), FOREIGN KEY (noClient) REFERENCES Client ON UPDATE CASCADE)

UPDATE ClientSET noClient = 100 WHERE noCLient = 10{Opération acceptée temporairement}UPDATE CommandeSET noClient = 100 WHERE noCLient = 10{Opération déclenchée automatiquement}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 12

Politiques SET NULL et SET DEFAULT

CREATE TABLE Commande(noCommande INTEGER NOT NULL, dateCommande DATE NOT NULL, noClient INTEGER NOT NULL, PRIMARY KEY (noCommande), FOREIGN KEY (noClient) REFERENCES Client ON DELETE SET NULL)

DELETE FROM Client WHERE noClient = 10{Opération acceptée temporairement}

UPDATE CommandeSET noClient = NULL WHERE noCLient = 10{Opération déclenchée automatiquement}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 13

SET DEFAULT

CREATE TABLE Commande(noCommande INTEGER NOT NULL, dateCommande DATE NOT NULL, noClient INTEGER DEFAULT 50 NOT NULL, PRIMARY KEY (noCommande), FOREIGN KEY (noClient) REFERENCES Client ON DELETE SET DEFAULT)

DELETE FROM Client WHERE noClient = 10{Opération acceptée temporairement}

UPDATE CommandeSET noClient = 50 WHERE noCLient = 10{Opération déclenchée automatiquement}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 14

Oracle

 Défaut –  ON DELETE NO ACTION –  ON UPDATE NO ACTION

  Supporte aussi –  ON DELETE CASCADE –  ON DELETE SET NULL (version 8i)

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 15

Autres contraintes

 CHECK au delà d ’une colonne  ASSERTION générale

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 16

CHECK intra-ligne

 Plusieurs colonnes de la même ligne  Les Articles dont le noArticle est supérieur à 90

ont un prix supérieur à $15.00 CREATE TABLE Article(noArticle INTEGER NOT NULL, description VARCHAR(20), prixUnitaire DECIMAL(10,2) NOT NULL, quantitéEnStock INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (noArticle), CHECK (noArticle <=90 OR prixUnitaire > 15.0))

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 17

Check inter-ligne d'une même table

  Concerne plusieurs lignes   Le prixUnitaire d'un Article ne peut dépasser le prix

moyen de plus de $40.00

  Vérifié uniquement pour la ligne touchée :la contrainte peut être violée !

  Pas supporté par Oracle

CREATE TABLE Article(noArticle INTEGER NOT NULL, description VARCHAR(20), prixUnitaire DECIMAL(10,2) NOT NULL, quantitéEnStock INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (noArticle), CHECK (prixUnitaire-20 <= (SELECT AVG(prixUnitaire) FROM Article)))

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 18

CHECK inter-tables

  Concerne plusieurs tables

  Vérifié uniquement pour la ligne touchée : la contrainte peut être violée !

  Pas supporté par Oracle

Prêt{Clé prim aire : idPrêt}idPrêtdatePrêtidMem bre

<<Table>>PrêtArchivé

{Clé prim aire: idPrêt}idPrêtdateRetouridExem plaire

<<Table>>

CREATE TABLE PrêtArchivé(idPrêt INTEGER NOT NULL, dateRetour DATE NOT NULL, idExemplaire INTEGER NOT NULL, PRIMARY KEY (idPrêt), FOREIGN KEY (idPrêt) REFERENCES Prêt,CHECK (dateRetour >= SELECT datePrêt

FROM PrêtWHERE Prêt.idPrêt = PrêtArchivé.idPrêt)

)

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 19

Nom de contrainte (clause CONSTRAINT)

 DROP CONSTRAINT contNoClient   SET CONSTRAINT contNoClient …   Identification de la contrainte qui est violée à

l ’exécution

CREATE TABLE Client(noCLIENT INTEGER NOT NULL, nomClient VARCHAR(15) NOT NULL, noTéléphone VARCHAR(15) NOT NULL,CONSTRAINT contNoClient CHECK(noClient >0 AND noClient < 100000))

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 20

Gâchettes (TRIGGER)

  Procédure –  déclenchée par événement pré-déterminé (INSERT, DELETE, UPDATE) –  exécutée au niveau serveur de BD

  BD active   Utilité

–  maintien de contraintes d ’intégrité   statique   dynamique   alternative aux mécanismes déclaratifs (CHECK, ASSERTION, ...)

–  préférer mécanisme déclaratif

–  maintien d ’éléments dérivés   colonnes dérivées   copies dans BD répartie   ...

–  historique des mises à jour   AUDIT

–  sécurité

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 21

Lorsqu'une augmentation du prixUnitaire d'un Article est tentée, il faut limiter l'augmentation à 10% du prix en cours

CREATE TRIGGER BUArticleBornerAugmentationPrixBEFORE UPDATE OF prixUnitaire ON ArticleREFERENCING

OLD ROW AS ligneAvantNEW ROW AS ligneAprès

FOR EACH ROWWHEN (ligneAprès.prixUnitaire > ligneAvant.prixUnitaire*1.1)BEGIN

ligneAprès.prixUnitaire = ligneAvant.prixUnitaire*1.1;END

UPDATE ArticleSET prixUnitaire = 15.99WHERE noArticle = 10

10 Cèdre en boule 10.99

noArticle description prixUnitaire

ligneAvant

10 Cèdre en boule 15.99ligneAprès 10 Cèdre en boule 12.09ligneAprès

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 22

Utilisation d'un TRIGGER pour le maintien d'une contrainte d'intégrité dynamique

 Empêcher une augmentation du prixUnitaire d'un Article au delà de 10% du prix en cours

 Oracle –  RAISE_APPLICATION_ERROR

CREATE TRIGGER BUArticleEmpêcherAugmentationPrixTropElevéeBEFORE UPDATE OF prixUnitaire ON ArticleREFERENCING

OLD ROW AS ligneAvantNEW ROW AS ligneAprès

FOR EACH ROWWHEN (ligneAprès.prixUnitaire > ligneAvant.prixUnitaire*1.1)BEGIN

souleverUneException;END

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 23

Utilisation d'un TRIGGER pour le maintien d'une contrainte d'intégrité statique

  0 < noClient < 100000

 N.B. CHECK est préférable !

CREATE TRIGGER BIUClientVérifierNoClientBEFORE INSERT OR UPDATE OF noClient ON ClientREFERENCING

NEW ROW AS ligneAprèsFOR EACH ROWWHEN (ligneAprès.noClient <=0) OR (ligneAprès.noClient > 100000)BEGIN

souleverUneException;END

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 24

Étude de cas

  Lors d'une nouvelle livraison, la quantité à livrer ne peut dépasser la quantité en stock disponible

CREATE TRIGGER BIDétLivVérifierQuantitéEnStockBEFORE INSERT ON DétailLivraisonREFERENCING

NEW ROW AS ligneAprèsFOR EACH ROWWHEN ligneAprès.quantitéLivrée > (SELECT quantitéEnStock FROM Article WHERE noArticle = ligneAprès.noArticle)BEGIN

souleverUneException;END

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 25

CHECK SQL2 inadéquat

CREATE TABLE DétailLivraison(noLivraison INTEGER NOT NULL, noCommande INTEGER NOT NULL, noArticle INTEGER NOT NULL, quantitéLivrée INTEGER NOT NULL, PRIMARY KEY (noLivraison,noCommande, noArticle), FOREIGN KEY (noLivraison) REFERENCES Livraison(noLivraison), FOREIGN KEY (noCommande, noArticle) REFERENCES LigneCommande(noCommande, noArticle),CHECK (0 <= SELECT quantitéEnStock-quantitéLivrée

FROM ArticleWHERE noArticle = DétailLivraison.noArticle)

)

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 26

Ne permettre que la modification de la quantitéLivrée dans la table DétailLiraison

CREATE TRIGGER BUDétLivEmpêcherModifBEFORE UPDATE OF noLivraison, noCommande, noArticle ON DétailLivraisonBEGIN

souleverUneException;END

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 27

Ajuster la quantitéEnStock

CREATE TRIGGER AIDétLivAjusterQuantitéEnStockAFTER INSERT ON DétailLivraisonREFERENCING

NEW ROW AS ligneAprèsFOR EACH ROWBEGIN

UPDATE ArticleSET quantitéEnStock = quantitéEnStock - ligneAprès.quantitéLivréeWHERE noArticle = ligneAprès.noArticle;

END

CREATE TRIGGER AUDétLivAjusterQuantitéEnStockAFTER UPDATE OF quantitéLivrée ON DétailLivraisonREFERENCING

OLD ROW AS ligneAvantNEW ROW AS ligneAprès

FOR EACH ROWBEGIN

UPDATE ArticleSET quantitéEnStock = quantitéEnStock - (ligneAprès.quantitéLivrée-ligneAvant.quantitéLivrée)WHERE noArticle = ligneAvant.noArticle;

END

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 28

TRIGGER de niveau STATEMENT

 Exécution du corps une seule fois pour plusieurs lignes mises à jours dans le même énoncé

CREATE TRIGGER BUDétLivEmpêcherModifBEFORE UPDATE OF noLivraison, noCommande, noArticle ON DétailLivraisonBEGIN

souleverUneException;END

REFERENCINGOLD TABLE AS nomAvantNEW TABLE AS nomAprès

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 29

Exécuter les TRIGGER BEFORE STATEMENTPour chaque ligne touchée par l'opération

Exécuter les TRIGGER BEFORE ROWExécuter l'opérationExécuter les TRIGGER AFTER ROW

Fin pourExécuter les TRIGGER AFTER STATEMENT

Ordre d'exécution des TRIGGER

 Attention aux circularités !

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 30

Limites des TRIGGER

 Ne peuvent être DEFERRED  Complexes à coder  Contraintes particulières aux dialectes

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 31

Particularités des TRIGGER Oracle

  Pas de SELECT dans le WHEN   :NEW, :OLD   Omettre le mot-clé ROW dans REFERENCING   Corps en PL/SQL (voir chapitre 4).   Syntaxe :nomColonne   Pas de COMMIT/ROLLBACK dans un TRIGGER

–  procédure PL/SQL RAISE_APPLICATION_ERROR   Intervalle [-20000, -20999] pour code d’erreur

  IF INSERTING, DELETING, UPDATING.   Événements non standards

–  INSTEAD OF, STARTUP, LOGON, ...

  Problème avec table en mutation (modifiée par l'événement déclencheur)   etc.

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 32

Problème des tables en mutation CREATE TABLE Statistiques (idStat INTEGER NOT NULL, nombreClients INTEGER NOT NULL, PRIMARY KEY (idStat)) CREATE TRIGGER AIMettreAJourNbClients After INSERT ON Client FOR EACH ROW DECLARE total INTEGER; BEGIN SELECT COUNT(*) INTO total FROM Client ; UPDATE Statistiques SET nombreClients = total WHERE idStat = ID_STAT_NB_CLIENTS; END

SQL> INSERT INTO Client VALUES (…) {Exception : Table Client en mutation}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 33

Problème des tables en mutation

  Solution 1: AUTONOMOUS_TRANSACTION!

!  Considère la transaction comme indépendante   La mise-à-jour peut être erronée car la nouvelle insertion n’est

pas considérée

CREATE TRIGGER AIMettreAJourNbClients After INSERT ON Client FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION; total INTEGER; BEGIN SELECT COUNT(*) INTO total FROM Client; UPDATE Statistiques SET nombreClients = total WHERE idStat = ID_STAT_NB_CLIENTS; COMMIT; END

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 34

Problème des tables en mutation

  Solution 2: TRIGGER de niveau STATEMENT

!

  On supprime le FOR EACH ROW

  La mise à jour est faite une seule fois à la fin

CREATE TRIGGER AIMettreAJourNbClients After INSERT ON Client DECLARE total INTEGER; BEGIN SELECT COUNT(*) INTO total FROM Client; UPDATE Statistiques SET nombreClients = total WHERE idStat = ID_STAT_NB_CLIENTS; END

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 35

Problème des tables en mutation

  Solution 3: Éviter le problème complètement

!

  Meilleure solution

  Pas toujours possible

CREATE TRIGGER AIMettreAJourNbClients After INSERT ON Client FOR EACH ROW BEGIN UPDATE Statistiques SET nombreClients = nombreClients+1 WHERE idStat = ID_STAT_NB_CLIENTS; END