7 Conception dans un contexte relationnel
Planification
Analyse
Conception
Spécification des besoins
Modèle conceptuel
Construction
Modèle physique
Mise en oeuvre
Schémas (LDD), modules codés et testés
Maintenance
Pourquoi ?
Quoi ?
Comment ?
Architecture
Matériel
– centralisé, 2-tier, 3-tier, réparti, entrepôt de données,...
– plate-formes (parallélisme)
– réseau
Logiciel
– couches
Interface, Contrôle, Domaine, Persistance, Réseau,…
– partition par sous-domaine
– classes d ’implantation/modules
Diagrammes de composantes UML
– répartition des composantes
Diagrammes de déploiement UML
Réutilisation de composantes
Interface à l ’utilisateur
– X-Windows, Windows, SWING...
Communication
– TCP/IP, CORBA, RMI, DCOM, ...
Persistance
– ODBC, JDBC, SGBD,...
Réalisation de la persistance
Constantes du programme d ’application
Fichiers (API du SGF)
Librairies spécialisées
SGBD
– souplesse, robustesse, intégrité,…
– approche privilégiée dans ce chapitre
SGBD relationnel SQL centralisé
Forces du relationnel
Accessibilité large
Maturité de la technologie
Fondements théoriques solides
Standard répandu (SQL)
Support solide de l'intégrité
Outils de développement
7.1 Conception du schéma
relationnel au niveau conceptuel
Schéma relationnel : niveau conceptuel
– tables
– colonnes
types, domaines, ...
– contraintes d ’intégrité
clés primaires, étrangères, ...
Input à la conception
– modèle conceptuel des données
(persistantes)
7.1.1 Première ébauche du
schéma : une table par classe
Personne
<<table>>
Membre
<<table>> PrêtEnCours
<<table>>
PrêtArchivé
<<table>>
Employé
<<table>>
Catégorie
<<table>>
Auteur
<<table>>
Editeur
<<table>>
Livre
<<table>> Exemplaire
<<table>>
Prêt
<<table>>
Utilisateur
<<table>>
7.1.2 Traduction des attributs
Attribut de la classe -> colonne de la table
Livre {Clé candidate: ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée
<<table>>
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
7.1.2.1 TRADUCTION DES CONTRAINTES D'IDENTIFICATION (UNIQUE)
Contrainte UNIQUE -> clé candidate relationnelle
– clé primaire ?
Livre {Clé candidate: ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée
<<table>>
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
7.1.2.2 TRADUCTION DES TYPES DE DONNÉES
Type OCL Type SQL2 Oracle 8
Boolean BIT(1) Non supporté (utiliser CHAR(1) + CHECK)
Integer INTEGER ou SMALLINT NUMBER(n)
String CHARACTER (CHAR) (n), CHARACTER
VARYING (VARCHAR) (n) VARCHAR2(n), LONG ou LONG VARCHAR (chaîne jusqu'à 2G), CLOB (chaîne jusqu'à 4G), NCLOB (chaîne pour caractères encodés sur plusieurs octets)
Real NUMERIC(p,s) (précision exacte),
DECIMAL(p,s), REAL, DOUBLE PRECISION, FLOAT(p)
NUMBER(p,s)
Enum{v1,…vn} CHARACTER (CHAR) ou VARCHER + CHECK … IN (v1,…,vn) (possibilité de création de domaine)
Domaine non supporté
DATE DATE inclut TIME
TIME
TIMESTAMP
BIT(n), BIT VARYING(n) RAW(n : max = 255), LONG RAW (binaire jusqu'à 2G), BLOB (binaire jusqu'à 4G)
BFILE (pointeur à un fichier externe)
Types de données déclarés
Domaine pas toujours supporté par le dialecte SQL
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
TypeDonnéesAnnée {Integer > 0 }
<<datatype>>
Livre {Clé candidate: ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée
<<table>>
DomaineAnnée {INTEGER CHECK value > 0 }
<<domain>>
7.1.2.3 TYPES ÉNUMÉRÉS
Petit domaine invariant
– création d ’un domaine VARCHAR + CHECK
Exemplaire
{Clé candidate : idExemplaire}
idExemplaire : VARCHAR(10) dateAchat : Date
statut : DomaineStatut
<<table>>
DomaineStatut
{VARCHAR(15) CHECK value IN ('prêté','disponible','retiré')}
<<domain>>
Exemplaire {UNIQUE: idExemplaire}
idExemplaire : String dateAchat : Date
statut : enum(prêté, disponible, retiré)
Création d ’une table
Gros domaine ou extensible
– création d ’une table à part
– utilisé comme liste de valeurs (LOV Designer)
– introduction d ’une clé primaire artificielle ?
Exemplaire
{Clé candidate : idExemplaire}
idExemplaire : VARCHAR(10) dateAchat : Date
statut : VARCHAR(15)
<<table>>
DomaineStatut {Clé primaire : statut}
statut : VARCHAR(15)
<<table>>
7.1.2.4 TYPES COMPLEXES
1. Représentation explicite des attributs du type complexe
Membre
adresse : typeDonnéesAdresse
typeDonnéesAdresse numéroCivique
numéroAppartement nomRue
nomVille nomProvince nomPays codePostal
<<datatype>>
Membre numéroCivique
numéroAppartement nomRue
nomVille nomProvince nomPays codePostal
<<table>>
2. Création d'une nouvelle table
N.B. Pas de partage de la même adresse !
Membre
{Clé primaire : idMembre}
idMembre
<<table>>
Adresse
{Clé primaire : idMembre}
idMembre numéroCivique numéroAppartement nomRue
nomVille nomProvince nomPays codePostal
<<table>>
Membre
adresse : typeDonnéesAdresse
typeDonnéesAdresse numéroCivique
numéroAppartement nomRue
nomVille nomProvince nomPays codePostal
<<datatype>>
7.1.2.5 QUALIFICATEUR
Colonne dans la table du rôle opposé
– voir 7.1.3.2
Groupe nbMaximumInscrits Cours
{UNIQUE:sigle}
sigle titre
nbCrédits 1 0..1
numéro session numéro
session
1 0..1
Groupe
{Clé primaire : sigle, numéro, session}
sigle numéro session
nbMaximumInscrits
<<table>>
Cours {Clé primaire :sigle}
sigle titre nbCrédits
<<table>>
7.1.2.6 DISCRIMINANT
Redondant ? Utilisateur
{UNIQUE :idUtilisateur}
idUtilisateur : String motPasse : String catégorieUtilisateur
Membre
téléphoneRésidence : String
$ nbMaxPrêts : Integer = 5
$ duréeMaxPrêts : Integer = 7 Employé
{UNIQUE : codeMatricule}
codeMatricule : String
catégorieEmployé : enum(bibliothécaire, commis)
{disjointe, complète}
Utilisateur {Clé candidate : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10)
catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
DomaineCatégorieUtilisateur
{VARCHAR(14) CHECK value IN ('employé, 'membre')}
<<domain>>
7.1.2.7 ATTRIBUT MULTIVALUÉ
Table à part
– clé étrangère + colonne pour l ’attribut
Petit tableau de taille fixe
– n colonnes (valeurs nulles)
Encodage
– invisible au SGBD
Oracle8
– VARRAY, NESTED TABLE
7.1.2.8 COMPRESSION DES VALEURS DES ATTRIBUTS DE GRANDE TAILLE
Supporté par le SGBD ?
Multimédia
7.1.2.9 CRÉATION DE TABLES SUPPLÉMENTAIRES POUR LES ATTRIBUTS DE CLASSE
MembreGénéral nbMaxPrêts : INTEGER = 5 duréeMaxPrêts : INTEGER = 7
<<table>>
Membre
téléphoneRésidence : String
$ nbMaxPrêts : Integer = 5
$ duréeMaxPrêts : Integer = 7
Membre
téléphoneRésidence : VARCHAR(15)
<<table>>
27/02/22 © Robert Godin. Tous droits réservés 21
7.1.3 Réalisation de l'identité par les clés primaires
MembreGénéral {Clé primaire : noSequence}
<<table>>
Personne
{Clé primaire : noSequence}
noSequence : INTEGER nom : VARCHAR2(20) prénom : VARCHAR2(20)
<<table>>
Membre {Clé primaire : noSequence}
noSequence : INTEGER
téléphoneRésidence : VARCHAR(15)
<<table>>
PrêtEnCours
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>>
PrêtArchivé
{Clé primaire : noSequence}
noSequence : INTEGER dateRetour : DATE
<<table>>
Employé {Clé primaire : noSequence}
noSequence : INTEGER {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
catégorieEmployé : DomaineCatégorieEmployé
<<table>>
Catégorie
<<table>>
Auteur
{Clé primaire : noSequence}
noSequence
<<table>>
Editeur
<<table>>
Livre {Clé primaire : ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée
<<table>> Exemplaire
{Clé primaire : idExemplaire}
idExemplaire : VARCHAR(10) dateAchat : Date
statut : DomaineStatut
<<table>>
Prêt
{Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
<<table>>
Utilisateur {Clé primaire : noSequence}
noSequence
{Clé candidate : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10)
catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
AuteurLivre
{Clé primaire : noSequence, ISBN}
noSequence ISBN
7.1.3.1 CRÉATION D'UNE CLÉ PRIMAIRE ARTIFICIELLE
De manière systématique ?
Mécanisme de SEQUENCE Oracle
PrêtArchivé
{Clé primaire : noSequence}
noSequence : INTEGER dateRetour : DATE
<<table>>
PrêtEnCours
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>>
Prêt
{Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
<<table>>
Prêt
datePrêt : Date
PrêtArchivé dateRetour : Date
PrêtEnCours
7.1.3.2 UTILISATION D'UN IDENTIFIANT NATUREL COMME CLÉ PRIMAIRE
1. Utilisation d'un identifiant naturel (UNIQUE)
Si identifiant naturel trop lourd
– introduire clé primaire artificielle Livre
{Clé candidate: ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée
<<table>>
Livre {Clé primaire: ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée
<<table>>
2. Utilisation du qualificateur
Groupe nbMaximumInscrits Cours
{UNIQUE:sigle}
sigle titre
nbCrédits 1 0..1
numéro session numéro
session
1 0..1
Groupe
{Clé primaire : sigle, numéro, session}
sigle numéro session
nbMaximumInscrits
<<table>>
Cours
{Clé primaire :sigle}
sigle titre
nbCrédits
<<table>>
7.1.3.3 IDENTIFIANT NATUREL POUR UNE SPÉCIALISATION
Éviter de changer de clé primaire dans le contexte d ’une hiérarchie de généralisation
Si la table du parent est omise
– considérer identifiant naturel de la
spécialisation
27/02/22 © Robert Godin. Tous droits réservés .
26
7.1.4 Traduction des associations
Prêt
{Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
noSequenceUtilisateur : INTEGER idExemplaire : VARCHAR(10)
<<table>>
Personne
{Clé primaire : noSequence}
noSequence : INTEGER nom : VARCHAR2(20) prénom : VARCHAR2(20)
<<table>>
Membre {Clé primaire : noSequence}
noSequence : INTEGER
téléphoneRésidence : VARCHAR(15)
<<table>>
PrêtEnCours
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>> PrêtArchivé
{Clé primaire : noSequence}
noSequence : INTEGER dateRetour : DATE
<<table>>
Employé {Clé primaire : noSequence}
noSequence : INTEGER {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
catégorieEmployé : DomaineCatégorieEmployé
<<table>>
Catégorie {Clé primaire : code}
code : VARCHAR(10) descripteur : VARCHAR(20) codeParent : VARCHAR(10)
<<table>>
Auteur
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>>
Editeur
{Clé primaire : nomEditeur}
nomEditeur : VARCHAR(20)
<<table>>
Livre {Clé primaire : ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée nomEditeur : VARCHAR(20) code : VARCHAR(10)
<<table>> Exemplaire
{Clé primaire : idExemplaire}
idExemplaire : VARCHAR(10) dateAchat : Date
statut : DomaineStatut ISBN : CHAR(13)
<<table>>
Utilisateur {Clé primaire : noSequence}
noSequence
{Clé candidate : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10)
catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
MembreGénéral {Clé primaire : noSequence}
<<table>>
AuteurLivre
{Clé primaire : noSequence, ISBN}
noSequence : INTEGER
{Clé candidate : ISBN, ordreAuteur}
ISBN : CHAR(13) ordreAuteur : INTEGER
<<table>>
{Un Auteur ne peut exister sans AuteurLivre}
{Un Livre ne peut exister sans AuteurLivre}
noSequenceUtilisateur
{Un Livre ne peut exister sans Exemplaire}
7.1.4.1 CAS GÉNÉRAL : TRADUCTION D'UNE ASSOCIATION PAR UNE TABLE
Auteur
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>> Livre
{Clé primaire : ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée
<<table>>
AuteurLivre
{Clé primaire : noSequence, ISBN}
noSequence : INTEGER ISBN : CHAR(13)
<<table>>
{Un Auteur ne peut exister
sans AuteurLivre} {Un Livre ne peut exister
sans AuteurLivre}
Auteur
1..* 1..*
1..* 1..*
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
7.1.4.2 TRADUCTION D'UN RÔLE
ORDONNÉ POUR UNE ASSOCIATION
Auteur
1..* 1..*
1..* 1..*
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée {ordonné}
A u teu r
{C lé p rim a ire : n o S e q u e n c e } n o S eq u e n c e : IN T E G E R
< < ta ble > >
A u te u rL iv re
{C lé p rim a ire : n o S e q u en c e , IS B N } n o S e q u e n c e : IN T E G E R
{C lé c a n d id a te : IS B N , o rd re A u te u r} IS B N : C H A R (1 3 )
o rd re A u te u r : IN T E G E R
< < ta b le > >
L ivre {C lé p rim a ire : IS B N } IS B N : C H A R (1 3 ) titre : V A R C H A R (5 0 )
a n n é e P a ru tio n : D o m a in e A n n é e
< < ta b le > >
7.1.4.3 CLASSE ASSOCIATIVE
Cours {UNIQUE : sigle}
sigle titre nbCrédits Etudiant
{UNIQUE : codePermanent}
codePermanent nom
prénom
* * * *
NoteObtenue note
session
Cours
{Clé primaire : sigle}
sigle titre nbCrédits
<<table>>
Etudiant
{Clé primaire : codePermanent}
codePermanent nom
prénom
<<table>>
NoteObtenue
{Clé primaire : codePermament, sigle}
codePermament sigle
note session
<<table>>
7.1.4.4 CAS UN À PLUSIEURS
1. Traduction par une table ?
Catégorie {UNIQUE: code}
code : String
descripteur : String
1 1 **
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
Livre {C lé prim aire : IS B N } IS B N : C H A R(13) titre : V A R C H A R (50 )
annéeP arution : D om aineA nné e
< < table> >
C atégorie {C lé prim aire : code}
code : V A R C H A R(10) descripteu r : V A R C H A R (20)
< < table> >
C atég orieLivre {C lé prim aire : IS B N } IS B N : C H A R(13) code : V A R C H A R(10 )
< < table> >
2. Traduction par l'ajout d'une clé étrangère à privilégier
Navigation plus performante
Catégorie {UNIQUE: code}
code : String
descripteur : String 1 1 **
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
Livre {Clé primaire : ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée code : VARCHAR(10)
<<table>>
Catégorie {Clé primaire : code}
code : VARCHAR(10)
descripteur : VARCHAR(20)
<<table>>
Renommer la clé
étrangère au besoin
Utilisateur {Clé primaire : noSequence}
noSequence
{Clé candidate : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10)
catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
noSequenceUtilisateur
Prêt {Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
noSequenceUtilisateur : INTEGER idExemplaire : VARCHAR(10)
<<table>>
7.1.4.5 CAS UN À UN
1. Une clé étrangère (du côté obligatoire)
Passeport
{UNIQUE : noPasseport}
noPasseport dateExpiration Citoyen
{UNIQUE : noAssurranceSociale}
noAssurranceSociale nom
prénom
0..1
1 0..1
1
Passeport {Clé primaire : noPasseport}
noPasseport dateExpiration
{Clé candidate : noAssurranceSociale}
noAssurranceSociale
<<table>>
Citoyen
{Clé primaire : noAssurranceSociale}
noAssurranceSociale nom
prénom
<<table>>
2. Une nouvelle table
Homme
{UNIQUE : noAssurranceSociale}
noAssurranceSociale nom
prénom
Femme
{UNIQUE : noAssurranceSociale}
noAssurranceSociale nom
prénom 0..1
0..1
0..1 0..1
grasAVie vieAGras
Mariage
Homme
{Clé primaire : noAssurranceSociale}
noAssurranceSociale nom
prénom
<<table>>
Femme
{Clé primaire : noAssurranceSociale}
noAssurranceSociale nom
prénom
<<table>>
Mariage
{Clé candidate : noAssSocFemme}
noAssSocFemme
{Clé candidate : noAssSocHomme}
noAssSocHomme
<<table>>
3. Fusion
Cas 1-1 obligatoire
7.1.4.6 CAS DE L'AGRÉGATION
Comme une association normale
Catégorie {UNIQUE: code}
code : String
descripteur : String
enfant
0..1
* parent 0..1
*
Catégorie {Clé primaire : code}
code : VARCHAR(10)
descripteur : VARCHAR(20) codeParent : VARCHAR(10)
<<table>>
codeParent
Composition
Cas 1-1
– ~ attribut complexe
Mode SQL CASCADE
Oracle8
– VARRAY, NESTED TABLE
7.1.5 Traduction des relations de généralisation/spécialisation
Délégation
Fusion
Concaténation
7.1.5.1 DÉLÉGATION
Personne
{Clé primaire : noSequence}
noSequence : INTEGER nom : VARCHAR2(20) prénom : VARCHAR2(20)
<<table>>
Membre {Clé primaire : noSequence}
noSequence : INTEGER
téléphoneRésidence : VARCHAR(15)
<<table>>
Employé {Clé primaire : noSequence}
noSequence : INTEGER {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
catégorieEmployé : DomaineCatégorieEmployé
<<table>>
Auteur
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>>
Utilisateur {Clé primaire : noSequence}
noSequence : INTEGER {Clé candidate : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10)
/ catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
{catégorieUtilisateur doit être cohérent avec la table d'appartenance de l'objet}
Changement de clé primaire ?
Extraire le téléphone résidence d'un Membre possédant l'idUtilisateur
12345
Personne
{Clé primaire : noSequence}
noSequence : INTEGER nom : VARCHAR2(20) prénom : VARCHAR2(20)
<<table>> Utilisateur
{Clé candidate : noSequence}
noSequence
{Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10)
catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
Employé {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
catégorieEmployé : DomaineCatégorieEmployé
<<table>>
Membre {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10)
téléphoneRésidence : VARCHAR(15)
<<table>>
Traduction de la contrainte {disjointe, complète}
Prêt
{Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
noSequenceUtilisateur : INTEGER idExemplaire : VARCHAR(10)
<<table>>
{Exclusives et une des deux est nécessaire}
PrêtArchivé
{Clé primaire : noSequence}
noSequence : INTEGER dateRetour : DATE
<<table>>
PrêtEnCours
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>>
Prêt datePrêt : Date {disjointe, complète}
PrêtArchivé dateRetour : Date
PrêtEnCours
7.1.5.1.1 Cas de la multi-classification et de l'héritage multiple
Auteur
{Clé prim aire : noS equence}
noS equence
<<table>>
Utilisateur {Clé prim aire : noS equenc e}
noS equenc e
{Clé c andidate : idUtilisateur}
idUtilis ateur : VARC HAR(10) m otP asse : VAR CHAR(10)
catégorieUtilisateur : D om aineC atégorieUtilis ateur
<<table>>
Em ployé {Clé prim aire : noS equenc e}
noS equenc e : INTEG ER {Clé c andidate : c odeM atricule}
codeM atric ule : CH AR(6)
catégorieE m ployé : D om aineC atégorieEm ployé
<<table>>
M em bre {Clé prim aire : noS equenc e}
noS equenc e : INT EG ER
téléphoneR ésidenc e : VARCH AR(15)
<<table>>
AuteurM em bre {Clé prim aire : noS equenc e}
noS equenc e
1. Créer une table de jointure
Alternatives
2. Identité commune sans table de jointure
3. Identité séparée et redondance
de données
7.1.5.2 ANALOGIE AVEC UNE ASSOCIATION UN À UN
Clé étrangère
– dans l ’enfant
– dans le parent ???
Approche Arc de Designer
Fusion
– vers le parent (approche par fusion)
– vers l ’enfant (approche par concaténation)
Nouvelle table ???
7.1.5.3 FUSION
Prêt {Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
noSequenceUtilisateur : INTEGER idExemplaire : VARCHAR(10)
{catégoriePrêt = 'prêtEnCours' ssi dateRetour nulle}
dateRetour[0..1] : DATE
catégoriePrêt : DomaineCatégoriePrêt
<<table>>
DomaineCatégoriePrêt
{VARCHAR(15) CHECK valeur IN ('prêtEnCours', 'prêtArchivé')}
<<domain>>
Prêt
{Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
noSequenceUtilisateur : INTEGER idExemplaire : VARCHAR(10)
<<table>>
{Exclusives et une des deux est nécessaire}
PrêtArchivé
{Clé primaire : noSequence}
noSequence : INTEGER dateRetour : DATE
<<table>>
PrêtEnCours
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>>
7.1.5.4 CONCATÉNATION
{La contrainte de clé primaire est globale pour les deux tables}
PrêtEnCours {Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
noSequenceUtilisateur : INTEGER idExemplaire : VARCHAR(10)
<<table>>
PrêtArchivé {Clé primaire : noSequence}
noSequence : INTEGER dateRetour : DATE datePrêt : DATE
noSequenceUtilisateur : INTEGER idExemplaire : VARCHAR(10)
<<table>>
Exemplaire
{Clé primaire : idExemplaire}
idExemplaire : VARCHAR(10) dateAchat : Date
statut : DomaineStatut ISBN : CHAR(13)
<<table>>
Utilisateur {Clé candidate : noSequence}
noSequence
{Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10)
catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
noSequenceUtilisateur noSequenceUtilisateur Prêt
{Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
noSequenceUtilisateur : INTEGER idExemplaire : VARCHAR(10)
<<table>>
{Exclusives et une des deux est nécessaire}
PrêtArchivé
{Clé primaire : noSequence}
noSequence : INTEGER dateRetour : DATE
<<table>>
PrêtEnCours
{Clé primaire : noSequence}
noSequence : INTEGER
<<table>>
Conserver une table
pour le parent ?
Cas d ’une référence au parent
Membre {Clé primaire : noSequence}
noSequence : INTEGER nom : VARCHAR2(20) prénom : VARCHAR2(20) {Clé candidate : idUtilisateur}
idUtilisatuer : VARCHAR(10) motPasse : VARCHAR(10)
téléphoneRésidence : VARCHAR(15)
<<table>>
Employé {Clé primaire : noSequence}
noSequence : INTEGER nom : VARCHAR2(20) prénom : VARCHAR2(20) {Clé candidate : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10)
catégorieEmployé : DomaineCatégorieEmployé {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
<<table>>
{exclusives}
noSequenceEmployé
noSequenceMembre
Prêt
{Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
noSequenceEmployé : INTEGER noSequenceMembre : INTEGER idExemplaire : VARCHAR(10)
<<table>>
7.1.5.5 TRADUCTION DES GÉNÉRALISATIONS POUR SYLERAT
Membre {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10)
téléphoneRésidence : VARCHAR(15)
<<table>>
PrêtEnCours {Clé primaire : noSequence}
noSequence : INTEGER datePrêt : DATE
idUtilisateur : VARCHAR(10) idExemplaire : VARCHAR(10)
<<table>>
PrêtArchivé {Clé primaire : noSequence}
noSequence : INTEGER dateRetour : DATE datePrêt : DATE
idUtilisateur : VARCHAR(10) idExemplaire : VARCHAR(10)
<<table>>
Employé {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
catégorieEmployé : DomaineCatégorieEmployé
<<table>>
Catégorie {Clé primaire : code}
code : VARCHAR(10) descripteur : VARCHAR(20) codeParent : VARCHAR(10)
<<table>>
Auteur
{Clé primaire : noSequence}
noSequence : INTEGER nom : VARCHAR2(20) prénom : VARCHAR2(20)
<<table>>
Editeur
{Clé primaire : nomEditeur}
<<table>>
Livre {Clé primaire : ISBN}
ISBN : CHAR(13) titre : VARCHAR(50)
annéeParution : DomaineAnnée nomEditeur : VARCHAR(20) code : VARCHAR(10)
<<table>> Exemplaire
{Clé primaire : idExemplaire}
idExemplaire : VARCHAR(10) dateAchat : Date
statut : DomaineStatut ISBN : CHAR(13)
<<table>>
Utilisateur {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10) nom : VARCHAR2(20) prénom : VARCHAR2(20)
/ catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
MembreGénéral {Clé primaire : noSequence}
<<table>>
AuteurLivre
{Clé primaire : noSequence, ISBN}
noSequence : INTEGER
{Clé candidate : ISBN, ordreAuteur}
ISBN : CHAR(13) ordreAuteur : INTEGER
<<table>>
{Un Auteur ne peut exister sans AuteurLivre}
{Un Livre ne peut exister sans AuteurLivre}
{Un Livre ne peut exister sans Exemplaire}
{Exclusives et une des deux est nécessaire}
{CatégorieUtilisateur doit être cohérente avec la table d'appartenance}
{Lors d'un retour le PrêtArchivé est généré à partir du PrêtEn Cours en réutilisant le même noSequence}
7.1.6 Traduction des autres contraintes
PrêtEnCours
{Clé primaire : idExemplaire}
idExemplaire : VARCHAR(10) datePrêt : DATE
idUtilisateur : VARCHAR(10)
<<table>>
PrêtArchivé
{Clé primaire : noSequence}
noSequence : INTEGER {dateRetour >= datePrêt}
dateRetour : DATE datePrêt : DATE
idUtilisateur : VARCHAR(10) idExemplaire : VARCHAR(10)
<<table>>
Exemplaire
{Clé primaire : idExemplaire}
idExemplaire : VARCHAR(10) dateAchat : Date
statut : DomaineStatut
<<table>>
MembreGénéral {Clé primaire : noSequence}
noSequence
nbMaxPrêts : INTEGER = 5 duréeMaxPrêts : INTEGER = 7
<<table>>
{statut = 'prêté' si et seulement si un Prêt EnCours fait référence à l'Exemplaire}
{Le nombre de PrêtEnCours d'un Membre <= nbMaxPrêts}
Utilisateur {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10) nom : VARCHAR2(20) prénom : VARCHAR2(20)
/ catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
Membre {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10)
téléphoneRésidence : VARCHAR(15)
<<table>>
7.1.7 Niveau de mise en œuvre des
contraintes d'intégrité : client ou serveur de BD ?
Robustesse
Interactivité
Performance
7.1.8 Représentation des
contraintes d'intégrité en SQL
Voir chap.7, volume I
Deux catégories
– Contrainte d'intégrité statique
respectée pour chacun des états de la BD
– Contrainte d'intégrité dynamique
contrainte sur changements d'états
7.1.8.1 CONTRAINTES STATIQUES
Mécanismes déclaratifs (à privilégier)
– PRIMARY KEY, UNIQUE, NOT NULL, DOMAIN, FOREIGN KEY, CHECK, ASSERTION
Procédural
– TRIGGER (SQL3)
plus complexe à coder
–
plus sujet à erreur
parfois plus performant
parfois inévitables (limite des mécanismes déclaratifs)
Contrainte sur le domaine d'une colonne
CREATE DOMAIN DomaineCatégorieUtilisateur AS
VARCHAR(14) CHECK(VALUE IN ('employé', 'membre')) CREATE TABLE Utilisateur
(idUtilisateur VARCHAR(10) NOT NULL,
motPasse VARCHAR(10) NOT NULL,
nom VARCHAR(20) NOT NULL,
prénom VARCHAR(20) NOT NULL,
catégorieUtilisateur DomaineCatégorieUtilisateur NOT NULL, PRIMARY KEY (idUtilisateur)
)
DomaineCatégorieUtilisateur
{VARCHAR(14) CHECK value IN ('employé, 'membre')}
<<domain>>
Utilisateur {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10) nom : VARCHAR2(20) prénom : VARCHAR2(20)
/ catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
Contrainte de clé primaire
CREATE TABLE Utilisateur
(idUtilisateur VARCHAR(10) NOT NULL,
…
PRIMARY KEY (idUtilisateur) )
Utilisateur {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10) nom : VARCHAR2(20) prénom : VARCHAR2(20)
/ catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
Contrainte de clé candidate
CREATE TABLE Employé
(idUtilisateur VARCHAR(10) NOT NULL, codeMatricule CHAR(6) NOT NULL,
catégorieEmployé DomaineCatégorieEmployé NOT NULL, PRIMARY KEY (idUtilisateur),
UNIQUE (codeMatricule),
FOREIGN KEY (idUtilisateur) REFERENCES Utilisateur )
Employé {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
catégorieEmployé : DomaineCatégorieEmployé
<<table>>
Contrainte d'intégrité référentielle
Employé {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
catégorieEmployé : DomaineCatégorieEmployé
<<table>>
Utilisateur {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10) nom : VARCHAR2(20) prénom : VARCHAR2(20)
/ catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
CREATE TABLE Employé
(idUtilisateur VARCHAR(10) NOT NULL, codeMatricule CHAR(6) NOT NULL,
catégorieEmployé DomaineCatégorieEmployé NOT NULL, PRIMARY KEY (idUtilisateur),
UNIQUE (codeMatricule),
FOREIGN KEY (idUtilisateur) REFERENCES Utilisateur )
Politique NO ACTION par défaut
Contrainte intra-ligne
CREATE TABLE PrêtArchivé
(noSequence INTEGER NOT NULL,
datePrêt DATE NOT NULL,
dateRetour DATE NOT NULL,
idUtilisateur VARCHAR(10) NOT NULL, idExemplaire VARCHAR(10) NOT NULL, PRIMARY KEY (noSequence),
FOREIGN KEY (idUtilisateur) REFERENCES Utilisateur, FOREIGN KEY (idExemplaire) REFERENCES Exemplaire, CHECK (dateRetour >= datePrêt)
)
PrêtArchivé
{Clé primaire : noSequence}
noSequence : INTEGER {dateRetour >= datePrêt}
dateRetour : DATE datePrêt : DATE
idUtilisateur : VARCHAR(10) idExemplaire : VARCHAR(10)
<<table>>
Autres cas
CHECK complexes
– non supporté par Oracle
ASSERTION
– non supporté par Oracle
TRIGGER
{Un Editeur ne peut exister sans qu'un Livre y fasse référence}
CREATE TABLE Editeur
(nomEditeur VARCHAR(20) NOT NULL,
ville VARCHAR(20) NOT NULL,
PRIMARY KEY (nomEditeur),
CHECK nomEditeur IN (SELECT nomEditeur FROM Livre) DEFERRABLE INITIALLY DEFERRED
)
CREATE TRIGGER BDULivreInterdiction BEFORE DELETE OR UPDATE ON Livre FOR EACH ROW
BEGIN
souleverUneException;
END
Ne peut être réalisée par TRIGGER seulement !
Exemple avec ASSERTION
Membre {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10)
téléphoneRésidence : VARCHAR(15)
<<table>>
{Le nombre de PrêtEnCours d'un Membre <= nbMaxPrêts}
MembreGénéral {Clé primaire : noSequence}
noSequence
nbMaxPrêts : INTEGER = 5 duréeMaxPrêts : INTEGER = 7
<<table>>
CREATE ASSERTION ContrainteNbMaxPrêts CHECK
((NOT EXISTS (SELECT *
FROM Membre, MembreGénéral
WHERE MembreGénéral.nbMaxPrêts >
(SELECT COUNT(*) FROM PrêtEnCours
WHERE Membre.idUtilisateur = PrêtEnCours.idUtilisateur))))
Réalisation avec TRIGGER
CREATE TRIGGER BIPrêtEnCoursVérifierNbMaxPrêts BEFORE INSERT ON PrêtEnCours
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
WHEN
((EXISTS
(SELECT * FROM MEMBRES
WHERE idUtilisateur = lignesAprès.idUtilisateur)) AND
((SELECT COUNT(*) FROM PrêtEnCours
WHERE ligneAprès.idUtilisateur=PrêtEnCours.idUtilisateur) >=
(SELECT nbMaxPrêts FROM MembreGénéral))) BEGIN
souleverUneException;
END
CREATE TRIGGER BUPrêtEnCours BEFORE UPDATE ON PrêtEnCours FOR EACH ROW
BEGIN
souleverUneException;
END
PrêtEnCours
{Clé primaire : idExemplaire}
idExemplaire : VARCHAR(10) datePrêt : DATE
idUtilisateur : VARCHAR(10)
<<table>>
{statut = 'prêté' si et seulement si un Prêt EnCours fait référence à l'Exemplaire}
Exemplaire
{Clé primaire : idExemplaire}
idExemplaire : VARCHAR(10) dateAchat : Date
statut : DomaineStatut ISBN : CHAR(13)
<<table>>
CREATE ASSERTION ContrainteStatutPrêté CHECK
((NOT EXISTS
((SELECT idExemplaire FROM Exemplaire
WHERE statut = 'prêté') EXCEPT (SELECT idExemplaire
FROM PrêtEnCours))) AND (NOT EXISTS
((SELECT idExemplaire
FROM PrêtEnCours) EXCEPT (SELECT idExemplaire
FROM Exemplaire
WHERE statut = 'prêté'))))
DEFERRABLE INITIALLY DEFERRED
Par TRIGGER : forcer le changement de statut
CREATE TRIGGER AIPrêtEnCoursModifierStatutExemplaire AFTER INSERT ON PrêtEnCours
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
BEGIN
UPDATE Exemplaire
SET statut = 'prêté'
WHERE idExemplaire = ligneAprès.idExemplaire;
END
CREATE TRIGGER ADPrêtEnCoursModifierStatutExemplaire AFTER DELETE ON PrêtEnCours
REFERENCING
OLD ROW AS ligneAvant FOR EACH ROW
BEGIN
UPDATE Exemplaire
SET statut = 'disponible'
WHERE idExemplaire = ligneAvant.idExemplaire;
END
Membre {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10)
téléphoneRésidence : VARCHAR(15)
<<table>>
Employé {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) {Clé candidate : codeMatricule}
codeMatricule : CHAR(6)
catégorieEmployé : DomaineCatégorieEmployé
<<table>>
Utilisateur {Clé primaire : idUtilisateur}
idUtilisateur : VARCHAR(10) motPasse : VARCHAR(10) nom : VARCHAR2(20) prénom : VARCHAR2(20)
/ catégorieUtilisateur : DomaineCatégorieUtilisateur
<<table>>
{Exclusives et une des deux est nécessaire}
{CatégorieUtilisateur doit être cohérente avec la table d'appartenance}
CREATE ASSERTION ContrainteGénéralisationUtilisateur CHECK
((NOT EXISTS (SELECT * FROM Utilisateur, Employé
WHERE catégorieUtilisateur = ‘membre’
AND Utilisateur.idUtilisateur = Employé.idUtilisateur)) AND
(NOT EXISTS (SELECT *
FROM Utilisateur, Membre
WHERE catégorieUtilisateur = ‘employé’
AND Utilisateur.idUtilisateur = Employé.idUtilisateur)) AND
(NOT EXISTS
((SELECT idUtilisateur FROM Utilisateur) EXCEPT
((SELECT idUtilisateur FROM Employé)
UNION (SELECT idUtilisateur FROM MEMBRE)))))
{CatégorieUtilisateur doit être cohérente avec la table d'appartenance} par TRIGGER
CREATE TRIGGER AIEmployéModifierCatégorie AFTER INSERT ON Employé
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
BEGIN
UPDATE Utilisateur
SET catégorieUtilisateur = 'employé'
WHERE idUtilisateur = ligneAprès.idUtilisateur;
END
CREATE TRIGGER AIMembreModifierCatégorie AFTER INSERT ON Membre
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
BEGIN
UPDATE Utilisateur
SET catégorieUtilisateur = 'membre'
WHERE idUtilisateur = ligneAprès.idUtilisateur;
END
{Exclusives et une des deux est nécessaire} par CHECK
CREATE TABLE Utilisateur
(idUtilisateur VARCHAR(10) NOT NULL, motPasse VARCHAR(10) NOT NULL,
nom VARCHAR(10) NOT NULL,
prénom VARCHAR(10) NOT NULL,
catégorieUtilisateur DomaineCatégorieUtilisateur NOT NULL, PRIMARY KEY (idUtilisateur),
CHECK
((idUtilisateur IN (SELECT idUtilisateur FROM Employé) OR idUtilisateur IN (SELECT idUtilisateur FROM Membre)) AND
NOT (idUtilisateur IN (SELECT idUtilisateur FROM Employé) AND idUtilisateur IN (SELECT idUtilisateur FROM Membre)))
DEFERRABLE INITIALLY DEFERRED )
Impossible avec TRIGGER non DEFERRABLE
7.1.8.2 CONTRAINTES DYNAMIQUES
Interdit de faire un prêt à un Membre qui possède un retard
CREATE TRIGGER BIPrêtEnCoursVérifierRetard BEFORE INSERT ON PrêtEnCours
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
WHEN
((EXISTS
(SELECT * FROM MEMBRES
WHERE idUtilisateur = lignesAprès.idUtilisateur))AND (EXISTS
(SELECT * FROM PrêtEnCours, MembreGénéral
WHERE ligneAprès.idUtilisateur = idUtilisateur AND (CURRENT_DATE - datePrêt) > duréeMaxPrêts)))
BEGIN
souleverUneException;
END
{le statut de l'Exemplaire doit être disponible avant qu'un prêt ne soit effectué}
CREATE TRIGGER BIPrêtEnCoursVérifierDisponibilité BEFORE INSERT ON PrêtEnCours
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
WHEN (EXISTS
(SELECT * FROM Exemplaire
WHERE ligneAprès.idExemplaire = idExemplaire AND statut <> 'disponible'))
BEGIN
souleverUneException;
END
Archivage des prêts lors d'un retour
CREATE TRIGGER ADPrêtEnCoursArchiverPrêt AFTER DELETE ON PrêtEnCours
REFERENCING
OLD ROW AS ligneAvant FOR EACH ROW
BEGIN
INSERT INTO PrêtArchivé VALUES
SELECT MAX(noSequence)+1, ligneAvant.datePrêt, CURRENT_DATE, ligneAvant.idUtilisateur,
ligneAvant.idExemplaire FROM PrêtArchivé;
END
7.1.9 Exemple de schéma SQL pour SyLeRat
Eviter la circularité des définitions
CREATE TABLE Utilisateur (…,
CHECK
((idUtilisateur IN (SELECT idUtilisateur FROM Employé) OR idUtilisateur IN (SELECT idUtilisateur FROM Membre)) AND
NOT (idUtilisateur IN (SELECT idUtilisateur FROM Employé) AND idUtilisateur IN (SELECT idUtilisateur FROM Membre)))
DEFERRABLE INITIALLY DEFERRED )
CREATE TABLE Employé (…,
FOREIGN KEY (idUtilisateur) REFERENCES Utilisateur )
CREATE TABLE Membre (…,
FOREIGN KEY (idUtilisateur) REFERENCES Utilisateur
)
Utilisation du ALTER TABLE
CREATE TABLE Utilisateur (…
)
CREATE TABLE Employé (…,
FOREIGN KEY (idUtilisateur) REFERENCES Utilisateur )
CREATE TABLE Membre (…,
FOREIGN KEY (idUtilisateur) REFERENCES Utilisateur )
ALTER TABLE Utilisateur
ADD CONSTRAINT contrainteGénéralisationComplèteDisjointe CHECK
((idUtilisateur IN (SELECT idUtilisateur FROM Employé) OR idUtilisateur IN (SELECT idUtilisateur FROM Membre)) AND
NOT (idUtilisateur IN (SELECT idUtilisateur FROM Employé) AND idUtilisateur IN (SELECT idUtilisateur FROM Membre)))
DEFERRABLE INITIALLY DEFERRED
Combinaison de TRIGGER
CREATE TRIGGER BIPrêtEnCoursVérifierNbMaxPrêts BEFORE INSERT ON PrêtEnCours
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
WHEN ((EXISTS
(SELECT * FROM MEMBRES
WHERE idUtilisateur = lignesAprès.idUtilisateur)) AND
… END
CREATE TRIGGER BIPrêtEnCoursVérifierRetard BEFORE INSERT ON PrêtEnCours
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
WHEN ((EXISTS
(SELECT * FROM MEMBRES
WHERE idUtilisateur = lignesAprès.idUtilisateur))AND
… END
CREATE TRIGGER BIPrêtEnCoursVérifierDisponibilité BEFORE INSERT ON PrêtEnCours
…
Contrôler l'ordre d'exécution
Améliorer la performance
CREATE TRIGGER BIPrêtEnCoursVérifierNbMaxRetardDisponibilité BEFORE INSERT ON PrêtEnCours
REFERENCING
NEW ROW AS ligneAprès FOR EACH ROW
WHEN
(((EXISTS
(SELECT * FROM MEMBRES
WHERE idUtilisateur = lignesAprès.idUtilisateur)) AND
((EXISTS
(SELECT * FROM PrêtEnCours, MembreGénéral
WHERE ligneAprès.idUtilisateur = idUtilisateur AND (CURRENT_DATE - datePrêt) > duréeMaxPrêts))
OR
((SELECT COUNT(*) FROM PrêtEnCours
WHERE ligneAprès.idUtilisateur=PrêtEnCours.idUtilisateur) >=
(SELECT nbMaxPrêts FROM MembreGénéral)) )
) OR
(EXISTS
(SELECT * FROM Exemplaire
WHERE ligneAprès.idExemplaire = idExemplaire AND statut <> 'disponible'))
) BEGIN
souleverUneException;
END
Une seule fois !
N.B. Contrôle plus fin avec PL/SQL
7.2 Conception du schéma
relationnel au niveau externe
Ce que l ’utilisateur voit
Sécurité
– utilisateurs, rôles, privilèges
– partir des cas d ’utilisation
Tables virtuelles
7.2.1 Tables virtuelles
Mécanisme d ’encapsulation
– isoler l ’utilisateur des détails du schéma
– indépendance logique des données
Mécanisme de sécurité
– privilège d ’accès à la table
virtuelle seulement
Exemple d ’encapsulation
CREATE VIEW VueMembre AS
SELECT Utilisateur.idUtilisateur, motPasse, nom, prénom, téléphoneRésidence
FROM Utilisateur, Membre
WHERE Membre.idUtilisateur = Utilisateur.idUtilisateur CREATE VIEW VueEmployé AS
SELECT Utilisateur.idUtilisateur, motPasse, nom, prénom, codeMatricule, catégorieEmployé
FROM Utilisateur, Employé
WHERE Employé.idUtilisateur = Utilisateur.idUtilisateur
CREATE VIEW Prêt AS
(SELECT NULL, datePrêt, NULL, idUtilisateur, idExemplaire FROM PrêtEnCours)
UNION
(SELECT * FROM PrêtArchivé)
Exemple de mécanisme de sécurité
CREATE VIEW MesPrêts AS SELECT *
FROM Prêts
WHERE idUtilisateur = CURRENT_USER
7.2.2 Réalisation des
contraintes de sécurité
Acteur (cas d ’utilisation) : ROLE SQL
– ROLE RôleAdministrateurSystème
accès à tout
– ROLE RôleCommisAuPrêt
tout en lecture (SELECT)
Membre, Utilisateur, PrêtEnCours, PrêtArchivé,
Exemplaire en écriture (INSERT, DELETE, UPDATE)
– ROLE RôleMembre
– ...
GRANT ROLE xxx to authorizationID
Utilisation de TRIGGER
Le prêt est interdit 1h00 et 7h00
CREATE TRIGGER BIPrêtEnCoursVérifierHeure BEFORE INSERT ON PrêtEnCours
FOR EACH ROW
WHEN (CURRENT_TIME > TIME '01:00:00') AND (CURRENT_TIME < TIME '07:00:00')
BEGIN
souleverUneException;
END
7.3 Niveau interne du schéma
relationnel : conception physique
Input
– schéma (niveau conceptuel) initial
– estimations des volumes de données
– architecture
contraintes SGBD
contraintes plate-forme
– charge de travail
exigences de performance
Output
– le « meilleur » schéma interne
solution approchée
7.3.1 Conception physique dans un contexte centralisé
Organisations primaires
Organisations
secondaires
Organisation primaire
Fichiers et paramètres d'allocation d'espace
– quel disque/site
architectures RAID
– taille de bloc
– taille de fichier
fixe
allocation dynamique
– taille des granules
Organisation primaire (suite)
Paramètres d'allocation d'espace aux tables
– quels fichiers ?
– taille des granules
– homogène / hétérogène
– colonne externe ? (multimédia)
chemin vers fichier externe
URL
Organisation primaire (suite)
Paramètres du mécanisme d'allocation d'espace aux lignes
– position dans le fichier
allocation sérielle, grappe, index primaire, hachage
réservation d ’espace
paramètres spécifiques à l ’organisation
– enregistrements
taille fixe/variable
chevauchant ou non
compression
cryptage
– gestion des identifiants d ’enregistrement (IDE)
Organisations secondaires
Chemins d ’accès supplémentaires
– référence par IDE
Index secondaire
Organisation multidimensionnelle
Listes
– SGBD réseau
Collections de références
– SGBD objet
7.3.2 Le processus de conception
Intrants
– schéma relationnel au niveau conceptuel
– volume des tables
estimation difficile
– charge de travail
partir des cas d ’utilisation
Sortie
– schéma interne « optimal »
Problème d ’optimisation complexe
Enjeux conflictuels
– lecture/écriture, espace/temps
Grande quantité de paramètres
Mesures approximatives
Evolution des paramètres
Solution approchée
– heuristiques
Surveillance et mise au point
7.3.3 Heuristiques de conception
Sous-ensemble des opérations
– en ordre d ’ importance
Négliger le coût des mises à jour
Négliger le coût en espace mémoire
Méthode gloutonne
Méthode gloutonne
Initialiser schémaInterne
– e.g. organisation sérielle pour chacune des tables
Pour chacune des opération i (en ordre de priorité)
– trouver meilleur plan P pour opération
iselon schémaInterne
– chercher amélioration de schémaInterne
qui permet de produire un meilleur plan P ’
sans pénaliser opération
1… opération
i-1– si P ’ meilleur que P
schémaInterne := schémaInterne amélioré
Comment améliorer ?
– heuristiques d ’amélioration
7.3.4 Sélection par égalité
SELECT ...
FROM T
WHERE X = uneValeurDeX
Heuristique
– Si
bonne sélectivité de X
volume de données suffisant
– 1. Hachage sur X
– 2. Index primaire ou index groupant sur X
– 3. Index secondaire sur X
– N.B. Conditions particulières
Exemple glouton
>>> sélectivité de ISBN
>>> volume de données
TempsES (S=H) = 11ms
– volume assez stable
TempsES (S=IP) = 44ms
– sélection par intervalle non pertinente
TempsES (S=IS) = 55ms
Opération de priorité 1:
SELECT *
FROM Livre
WHERE ISBN = unISBN
Hachage<{Livre},{ISBN}>
Livre
<<table>>
Exemple
Meilleur plan P avec schéma interne précédent
–
TempsES (BAL) > 50 010ms (meilleur cas)
sélectivité de code = 1/4000
volume de données suffisant
TempsES (S=H) = 143ms
–
conflit avec hachage sur ISBN
TempsES (S=IP) = 242ms
–
conflit ...
TempsES (S=IS) = 2827ms
–
seule possibilité pour éviter de pénaliser 1
Opération de priorité 2:
SELECT *
FROM Livre
WHERE code = unCode
Hachage<{Livre},{ISBN}>
Livre
<<table>>
IndexSecondaire<Livre,{code}>
Glouton : temps moyen sous-optimal
Hypothèse
– sélection par ISBN : 50 fois par jour
– sélection par code : 30 fois par jour
– moyenne : (50*11 + 30*2827)/80 = 1067ms
Pénaliser un peu opération 1…
– moyenne : (50*55 + 30*143)/80 = 88ms
Hachage<{Livre},{code}>
Livre
<<table>>
IndexSecondaire<Livre,{ISBN}>
Meilleur plan P avec schéma interne précédent
– TempsES (S=IS sur code) = 2827ms
TempsES ( S=IS sur la clé composée {code, annéeParution} ) = 99ms
N.B. Index sur {code, annéeParution} utilisé pour :
Opération de priorité 3:
SELECT *
FROM Livre
WHERE code = unCode AND annéeParution = uneAnnée
Hachage<{Livre},{ISBN}>
Livre
<<table>>
IndexSecondaire<Livre,{code, annéeParution}>
Opération de priorité 2:
SELECT *
FROM Livre
code = unCode
Indexer les colonnes individuelles ?
TempsES(S) = 3 509ms
Hachage<{Livre},{ISBN}>
Livre
<<table>>
IndexSecondaire<Livre,{code}>
IndexSecondaire<Livre,{annéeParution}>
Opération de priorité 3:
SELECT *
FROM Livre
WHERE code = unCode AND annéeParution = uneAnnée
Meilleur plan P avec schéma interne précédent
– TempsES (BAL) > 50 010ms (meilleur cas)
TempsES ( S=IS sur annéeParution ) = 223 377 ms
Opération de priorité 4:
SELECT *
FROM Livre
WHERE annéeParution = uneAnnée
Hachage<{Livre},{ISBN}>
Livre
<<table>>
IndexSecondaire<Livre,{code, annéeParution}>