8 Conception du schéma relationnel et
génération du code (LDD) SQL avec Designer
Database Design Transformer (Design Wizard )
Design Editor
PL/SQL
Générateur de code SQL du schéma
(DDL)
8.1 Création d'un DATABASE et d'un
propriétaire du schéma
8.2 Génération d'un schéma brut avec le
Database Design Transformer
1ière passe
2ième passe
8.2.1 Réalisation de l'identité
Si option Create surrogate keys for all new tables
– crée une clé primaire artificielle (voir 7.1.3.1)
[nomTable]_ID
SEQUENCE associée
Sinon
– Si identifiant primaire existe
transforme en clé primaire
–
tient compte des associations identifiantes – Sinon
crée une clé primaire artificielle
8.2.2 Traduction des associations
*-*
– nouvelle table
1-*
– clé étrangère du côté plusieurs
1-1
– clé étrangère : quel côté ?
1. côté obligatoire
2. plus haut volume
3. ordre alphabétique
8.2.3 Embryon de schéma interne
Index secondaire sur clé étrangère
Pas sur clé primaire ou UNIQUE
– automatique avec Oracle
Volumes
– entité => table
– ajustements à apporter
8.3 Édition du schéma avec le Design Editor
Bouton Cancel
Menu File New Server Model
Diagram
Menu Edit Include
Tables/Views/Snapshots /Foreign
Keys
AUTEURS
NOM PRÉNOM AUT_ID AUT_TYPE
AUTEURS_LIVRES
CATÉGORIES
CODE DESCRIPTEUR CODE_PARENT
EDITEURS
NOM_EDITEUR VILLE
EMPLOYÉS
CODE_MATRICULE CATÉGORIE_EMPLOYÉ EMP_ID
EXEMPLAIRES
ID_EXEMPLAIRE DATE_ACHAT STATUT ISBN EXE_PK
LIVRES
ISBN TITRE
ANNÉE_PARUTION NOM_EDITEUR CODE
MEMBRE_GÉNÉRAL
NB_MAX_PRÊTS DURÉE_MAX_PRÊTS MEG_ID
MEMBRES
TÉLÉPHONE_RESIDENCE MEM_ID
PRÊTS_ARCHIVÉS
DATE_PRÊT DATE_RETOUR PA_ID PA_TYPE ID_UTILISATEUR ID_EXEMPLAIRE
PRÊTS_EN_COURS
DATE_PRÊT PEC_ID ID_UTILISATEUR ID_EXEMPLAIRE
UTILISATEURS
NOM PRÉNOM ID_UTILISATEUR MOT_PASSE EMP_ID MEM_ID
PA_UTI_FK
PA_EXE_FK
PEC_UTI_FK
PEC_EXE_FK
AUT_LIV_AUT_FK
UTI_EMP_FK
AUT_LIV_LIV_FK
UTI_MEM_FK
CAT_CAT_FK EXE_LIV_FK
LIV_EDI_FK LIV_CAT_FK
Conventions graphiques
Propriétés des colonnes
Indicateurs du mécanisme de gestion de l ’intégrité référentielle
Symbole Signification
* Colonne obligatoire o Colonne optionnelle
# Colonne faisant partie de la clé primaire
Symbole Signification
- RESTRICT
CASCADE
o NULLIFY
DEFAULT
? Clé étrangère non modifiable
Menu Options
Show/Hide
8.3.1 Édition des
caractéristiques d'une table
Menu Options Use Property
Palette
8.3.2 Spécification des propriétés de volume à
l'aide du mode Property Palette
8.3.3 Édition des colonnes
Valeur de défaut
Menu Options Use Property
Palette
8.3.4 Insertion d'une nouvelle
colonne dans une table
Création d ’un domaine pour le
discriminant CATÉGORIE_UTILISATEUR
Supprimer la colonne
AUT_TYPE de la table
AUTEURS
Menu Utilities Force Delete
8.3.5 Spécification d'un mécanisme de
dérivation pour une colonne dérivable
Sélectionnez SQL Expression
dans la propriété Derivation
Expression Type
8.3.7 Édition des contraintes de clé primaire (PRIMARY KEY)
Bouton # dans le rectangle de la table PRÊT_EN_COURS
PRÊTS_EN_COURS
DATE_PRÊT
ID_UTILISATEUR
ID_EXEMPLAIRE
PEC_PK
la ligne # PEC_PK
PRÊTS_EN_COURS
DATE_PRÊT ID_UTILISATEUR ID_EXEMPLAIRE PEC_PK
8.3.7.1 CRÉATION D'UNE
CONTRAINTE DE CLÉ CANDIDATE
8.3.8 Édition des contraintes d'intégrité
référentielle (FOREIGN KEY)
8.3.8.3 CRÉATION D'UNE NOUVELLE CONTRAINTE
D'INTÉGRITÉ RÉFÉRENTIELLE
8.3.9 Définition d'une
contrainte CHECK
8.3.10 Création d'un TRIGGER
(avec le bouton de droite de la souris) sur le
bouton TRIGGER dans le rectangle de la table
PRÊTS_EN_COURS
8.3.11 Édition du code PL/SQL
avec le Logic Editor
Menu Edit Logic
Menu Utilities Check
Syntax
8.3.12 Particularités des TRIGGER Oracle
Pas de SELECT imbriqué dans le WHEN
Par défaut
– NEW : ligne après la mise à jour (NEW ROW)
– OLD : ligne avant la mise à jour (OLD ROW)
Corps du TRIGGER
– PL/SQL (interface avec JAVA dans Oracle8i)
Précéder la colonne du « : » le corps du
TRIGGER
Exemple
CREATE TRIGGER ADPRÊTSENCOURSMODIFSTATUTARCH AFTER DELETE
ON PRÊTS_EN_COURS FOR EACH ROW
BEGIN
UPDATE EXEMPLAIRES
SET STATUT = 'disponible'
WHERE ID_EXEMPLAIRE = :OLD.ID_EXEMPLAIRE;
-- La syntaxe :OLD.ID_EXEMPLAIRE fait référence à la valeur de la ligne -- avant la suppression de la ligne
INSERT INTO PRÊTS_ARCHIVÉS VALUES
(PA_SEQ.NEXTVAL, :OLD.DATE_PRÊT, SYSDATE, :OLD.ID_UTILISATEUR, :OLD.ID_EXEMPLAIRE, SYSDATE-:OLD.DATE_PRÊT);
-- PA_SEQ.NEXTVAL retourne la prochaine valeur de la SEQUENCE PA_SEQ END ADPRÊTSENCOURSMODIFSTATUTARCH;
8.3.13 Utilisation de PL/SQL
CREATE TRIGGER BIPRÊTENCOURSVERIFCOND BEFORE INSERT
ON PRÊTS_EN_COURS FOR EACH ROW BEGIN
DECLARE -- déclaration de variables PL/SQL
statutExemplaire EXEMPLAIRES.STATUT%TYPE;
--%TYPE retourne le type de la colonne idUtilisateurMembre MEMBRES.ID_UTILISATEUR%TYPE;
nombrePrêtsEnCours INTEGER;
nombreMaximalPrêts INTEGER;
duréeMaximalePrêts INTEGER;
nombreRetards INTEGER;
exemplaireNonDisponible EXCEPTION;
nombreMaximalAtteint EXCEPTION;
prêtEnRetard EXCEPTION;
BEGIN
-- Vérifier si statut de l'exemplaire = disponible SELECT STATUT
INTO statutExemplaire
-- La clause INTO permet de récupérer les valeurs des colonnes -- du SELECT dans des variables PL/SQL
FROM EXEMPLAIRES
WHERE ID_EXEMPLAIRE = :NEW.ID_EXEMPLAIRE FOR UPDATE; -- pour sérialisabilité IF statutExemplaire <> 'disponible' THEN
RAISE exemplaireNonDisponible;
-- le RAISE soulève une exception traitée dans la section EXCEPTION END IF;
Suite
-- Vérifier si l'emprunteur est un membre SELECT ID_UTILISATEUR
INTO idUtilisateurMembre
FROM MEMBRES WHERE ID_UTILISATEUR = :NEW.ID_UTILISATEUR;
IF SQL%FOUND THEN
-- L'attribut SQL%FOUND permet de savoir si le dernier SELECT a retourné -- au moins une ligne
-- Vérifier si le nombre maximal d'emprunts est atteint LOCK TABLE PRÊTS_EN_COURS IN SHARE ROW EXCLUSIVE MODE;
SELECT COUNT(*)
INTO nombrePrêtsEnCours FROM PRÊTS_EN_COURS
WHERE ID_UTILISATEUR = :NEW.ID_UTILISATEUR;
SELECT NB_MAX_PRÊTS, DURÉE_MAX_PRÊTS
INTO nombreMaximalPrêts, duréeMaximalePrêts FROM MEMBRE_GÉNÉRAL;
IF nombrePrêtsEnCours >= nombreMaximalPrêts THEN RAISE nombreMaximalAtteint;
END IF;
-- Vérifier s'il y a un retard SELECT COUNT(*)
INTO nombreRetards FROM PRÊTS_EN_COURS
WHERE ID_UTILISATEUR = :NEW.ID_UTILISATEUR AND (SYSDATE-DATE_PRÊT) > duréeMaximalePrêts;
IF nombreRetards > 0 THEN RAISE prêtEnRetard;
END IF;
END IF;
EXCEPTION
WHEN exemplaireNonDisponible THEN
RAISE_APPLICATION_ERROR(-20100,'l''exemplaire n''a pas le statut disponible');
WHEN nombreMaximalAtteint THEN
RAISE_APPLICATION_ERROR(-20101,'le nombre maximal d''emprunts est atteint');
WHEN prêtEnRetard THEN
RAISE_APPLICATION_ERROR(-20102,'emprunt interdit à cause de retard');
WHEN OTHERS THEN
Attention ! La clause INTO provoque une exception si le SELECT ne retourne rien
BLOC PL/SQL
[DECLARE
déclaration [déclaration] ...
BEGIN
séquenceEnoncés [EXCEPTION
exception_énoncé [exception_énoncé] ...]
END
Déclaration de variables PL/SQL (DECLARE)
statutExemplaire EXEMPLAIRES.STATUT%TYPE;
Transfert d'une valeur de colonne d'un SELECT dans une variable (clause INTO)
SELECT STATUT
INTO statutExemplaire FROM EXEMPLAIRES
WHERE ID_EXEMPLAIRE = :NEW.ID_EXEMPLAIRE
FOR UPDATE;
Structure de contrôle IF
IF statutExemplaire <> 'disponible' THEN RAISE exemplaireNonDisponible;
END IF;
Traitement d'exception (EXCEPTION, RAISE)
exemplaireNonDisponible EXCEPTION;
IF statutExemplaire <> 'disponible' THEN RAISE exemplaireNonDisponible;
END IF;
WHEN exemplaireNonDisponible THEN
RAISE_APPLICATION_ERROR(-20100,'l''exemplaire n''a pas
le statut disponible');
Attribut de curseur
implicite SQL%FOUND
SELECT ID_UTILISATEUR INTO idUtilisateurMembre
FROM MEMBRES WHERE ID_UTILISATEUR = :NEW.ID_UTILISATEUR;
IF SQL%FOUND THEN
…
Autres attributs
– %NOTFOUND
– %ISOPEN
– %ROWCOUNT
Curseur en PL/SQL (CURSOR)
CURSOR lignesPrêts(idUtilisateur PRÊTS_EN_COURS.ID_UTILISATEUR%TYPE)IS SELECT DATE_PRÊT
FROM PRÊTS_EN_COURS
WHERE ID_UTILISATEUR = idUtilisateur;
OPEN lignesPrêts(:NEW.ID_UTILISATEUR);
LOOP
FETCH lignesPrêts INTO datePrêt;
EXIT WHEN lignesPrêts%NOTFOUND;
IF (SYSDATE-datePrêt > duréeMaximalePrêts) THEN RAISE prêtEnRetard;
END IF;
nombrePrêtsEnCours := nombrePrêtsEnCours + 1;
END LOOP;
Fonction PL/SQL
FUNCTION fStatutExemplaire
(unIdExemplaire IN EXEMPLAIRES.ID_EXEMPLAIRE%TYPE) RETURN EXEMPLAIRES.STATUT%TYPE IS
statutExemplaire EXEMPLAIRES.STATUT%TYPE;
BEGIN
SELECT STATUT
INTO statutExemplaire FROM EXEMPLAIRES
WHERE ID_EXEMPLAIRE = unIdExemplaire;
RETURN statutExemplaire;
END fStatutExemplaire;
Création au niveau du serveur (CREATE FUNCTION)
CREATE FUNCTION fStatutExemplaire
(unIdExemplaire IN EXEMPLAIRES.ID_EXEMPLAIRE%TYPE) RETURN EXEMPLAIRES.STATUT%TYPE IS
statutExemplaire EXEMPLAIRES.STATUT%TYPE;
BEGIN
SELECT STATUT
INTO statutExemplaire FROM EXEMPLAIRES
WHERE ID_EXEMPLAIRE = unIdExemplaire;
RETURN statutExemplaire;
END fStatutExemplaire;
CREATE OR REPLACE fStatutExemplaire…
DROP FUNCTION fStatutExemplaire
Appel de fonction
IF
fStatutExemplaire (:NEW.ID_EXEMPLAIRE)<> 'disponible' THEN RAISE exemplaireNonDisponible;
END IF;
Procédure PL/SQL
PROCEDURE pModifierStatutExemplaire
(unIdExemplaire EXEMPLAIRES.ID_EXEMPLAIRE%TYPE, unStatut EXEMPLAIRES.STATUT%TYPE) IS
BEGIN
UPDATE EXEMPLAIRES
SET STATUT = unStatut
WHERE ID_EXEMPLAIRE = unIdExemplaire;
END pModifierStatutExemplaire ;
EXECUTE pModifierStatutExemplaire(1, 'disponible');
CREATE PROCEDURE pModifierStatutExemplaire…
Package PL/SQL
CREATE PACKAGE nomPaquetage AS
listeDesSignaturesDesFonctions&Procédures END nomPaquetage ;
CREATE PACKAGE BODY nomPaquetage AS délaration [déclaration]…
BEGIN
séquenceÉnoncésInitialisation END nomPaquetage;
nomPaquetage.nomObjet
Déboguage du code PL/SQL
SHOW ERRORS
SQL> SELECT text
2 FROM USER_SOURCE
3 WHERE name = 'FSTATUTEXEMPLAIRE' AND type = 'FUNCTION' 4 ORDER BY line;
TEXT--- ---
FUNCTION fStatutExemplaire (unIdExemplaire EXEMPLAIRES.ID_EXEMPLAIRE%TYPE) RETURN EXEMPLAIRES.STATUT%TYPE IS
statutExemplaire EXEMPLAIRES.STATUT%TYPE;
BEGIN
SELECT STATUT
INTO statutExemplaire FROM EXEMPLAIRES
WHERE ID_EXEMPLAIRE = unIdExemplaire;
RETURN statutExemplaire;
END fStatutExemplaire;
CREATE OR REPLACE PROCEDURE afficherPrêtsEnCours
(unIdUtilisateur PRÊTS_EN_COURS.ID_UTILISATEUR%TYPE) IS laDatePrêt PRÊTS_EN_COURS.DATE_PRÊT%TYPE;
leIdExemplaire PRÊTS_EN_COURS.ID_EXEMPLAIRE%TYPE;
leISBN EXEMPLAIRES.ISBN%TYPE;
nombrePrêtsEnCours INTEGER;
duréeMaximalePrêts INTEGER;
CURSOR lignesPrêts(idUtilisateur PRÊTS_EN_COURS.ID_UTILISATEUR%TYPE)IS SELECT DATE_PRÊT, PRÊTS_EN_COURS.ID_EXEMPLAIRE, ISBN
FROM PRÊTS_EN_COURS, EXEMPLAIRES WHERE ID_UTILISATEUR = idUtilisateur AND
PRÊTS_EN_COURS.ID_EXEMPLAIRE = EXEMPLAIRES.ID_EXEMPLAIRE;
BEGIN
DBMS_OUTPUT.PUT('Prêts en cours pour utilisateur #:');
DBMS_OUTPUT.PUT_LINE(unIdUtilisateur);
SELECT DURÉE_MAX_PRÊTS INTO duréeMaximalePrêts FROM MEMBRE_GÉNÉRAL;
LOCK TABLE PRÊTS_EN_COURS IN SHARE MODE;
nombrePrêtsEnCours := 0;
OPEN lignesPrêts(unIdUtilisateur);
LOOP
FETCH lignesPrêts INTO laDatePrêt, leIdExemplaire, leISBN;
EXIT WHEN lignesPrêts%NOTFOUND;
DBMS_OUTPUT.PUT('datePrêt :');
DBMS_OUTPUT.PUT(laDatePrêt);
DBMS_OUTPUT.PUT(' idExemplaire :');
DBMS_OUTPUT.PUT(leIdExemplaire );
DBMS_OUTPUT.PUT(' ISBN :');
DBMS_OUTPUT.PUT_LINE(leISBN);
IF (SYSDATE-laDatePrêt> duréeMaximalePrêts) THEN DBMS_OUTPUT.PUT('Ce prêt est en retard de ');
DBMS_OUTPUT.PUT(TRUNC(SYSDATE)-TRUNC(laDatePrêt)-duréeMaximalePrêts);
DBMS_OUTPUT.PUT_LINE(' jour(s)');
END IF;
nombrePrêtsEnCours := nombrePrêtsEnCours + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Nombre de prêts en cours :' || TO_CHAR(nombrePrêtsEnCours) );
Exécution sous SQL*plus
SQL> SET SERVEROUTPUT ON
SQL> EXECUTE afficherPrêtsEnCours(1);
Prêts en cours pour utilisateur #:1
datePrêt :15/10/99 idExemplaire :1 ISBN :3-333-3333333 Ce prêt est en retard de 82 jour(s)
datePrêt :15/10/99 idExemplaire :3 ISBN :0-201-12227-8 Ce prêt est en retard de 82 jour(s)
Nombre de prêts en cours :2
Procédure PL/SQL terminée avec succès.
Oracle 8i
Intégration de Java au niveau du serveur
– machine virtuelle Java (JVM)
– pilote JDBC
– support des architectures de composantes
CORBA (Common Object Request Broker Architecture)
EJB (Enterprise Java Beans)
Procédures/fonctions de serveur en Java
Composantes CORBA et EJB
8.3.14 Création d'une
table virtuelle (VIEW)
VUEMEMBRE
UTILISATEURS_ID_UTILISATEUR MOT_PASSE
NOM PRÉNOM
TÉLÉPHONE_RESIDENCE
VUEMEMBRE
ID_UTILISATEUR MOT_PASSE NOM PRÉNOM
8.3.15 Maintenance de
Sequence Oracle
8.3.16 Édition des index secondaires
LIVRES
ISBN TITRE
ANNÉE_PARUTION NOM_EDITEUR CODE
LIV_EDI_FK_I LIV_CAT_FK_I