Gestion des intervenants

SQL sous Oracle

Soit le MCD ci-après.

MCD "Cours et Intervenants"

Question

Produisez le MLD relationnel.

Solution

1
tIntervenant (#pknom:varchar, prenom:varchar, poste:integer)
2
tCours (#pkannee:2000..2100, #pknum:integer, titre:varchar, type:C|TD|TP, fkintervenant=>tIntervenant, debut:date)

Question

Produisez un code SQL qui fonctionne pour Oracle et pour PostgreSQL.

Solution

1
CREATE TABLE tIntervenant (
2
pknom VARCHAR(255) PRIMARY KEY,
3
prenom VARCHAR(255) NOT NULL,
4
poste INTEGER
5
);
6
7
CREATE TABLE tCours (
8
pkannee INTEGER check (pkannee>2000 and pkannee<2100),
9
pknum INTEGER,
10
titre VARCHAR(255),
11
type CHAR(2) CHECK (type='C' OR type='TD' OR type='TP') NOT NULL,
12
fkintervenant VARCHAR(255) REFERENCES tIntervenant(pknom) NOT NULL,
13
debut DATE,
14
PRIMARY KEY(pkannee, pknum)
15
);
Remarque

Sous Oracle il est recommandé d'utiliser le type VARCHAR2, mais pour conserver un code standard, on préférera le type standard VARCHAR.

Particularités LDD

Question

Produisez un code spécialisé pour Oracle.

Solution

1
CREATE TABLE tIntervenant (
2
pknom VARCHAR2(255) PRIMARY KEY,
3
prenom VARCHAR2(255) NOT NULL,
4
poste NUMBER(4)
5
);
6
7
CREATE TABLE tCours (
8
pkannee NUMBER(4) check (pkannee>2000 and pkannee<2100),
9
pknum INTEGER,
10
titre VARCHAR2(255),
11
type CHAR(2) CHECK (type='C' OR type='TD' OR type='TP') NOT NULL,
12
fkintervenant VARCHAR2(255) REFERENCES tIntervenant(pknom) NOT NULL,
13
debut DATE,
14
PRIMARY KEY(pkannee, pknum)
15
);
Remarque

On utilise le type VARCHAR2 recommandé par la documentation, et l'on peut aussi utiliser le type NUMBER pour spécifier des types numériques limités.

Question

Vérifier la création de vos tables dans le dictionnaire de données (existence de la table, description de la table, et liste des contraintes).

Indice

1
TABLE_NAME                   
2
------------------------------
3
TINTERVENANT                   
4
TCOURS                        

Indice

1
Name          Null     Type          
2
------------- -------- ------------- 
3
PKANNEE       NOT NULL NUMBER(4)     
4
PKNUM         NOT NULL NUMBER(38)    
5
TITRE                  VARCHAR2(255) 
6
TYPE          NOT NULL CHAR(2)       
7
FKINTERVENANT NOT NULL VARCHAR2(255) 
8
DEBUT                  DATE

Indice

1
TABLE_NAME                     TYPE CONSTRAINT_NAME                SEARCH_CONDITION
2
------------------------------ ---- ------------------------------ ----------------------------------
3
TCOURS                         C    SYS_C00411567                  "FKINTERVENANT" IS NOT NULL
4
TCOURS                         C    SYS_C00411568                  pkannee>2000 and pkannee<2100
5
TCOURS                         C    SYS_C00411569                  type='C' OR type='TD' OR type='TP'
6
TCOURS                         C    SYS_C00411566                  "TYPE" IS NOT NULL
7
TCOURS                         P    SYS_C00411570
8
TCOURS                         R    SYS_C00411571
9
TINTERVENANT                   C    SYS_C00411564                  "PRENOM" IS NOT NULL
10
TINTERVENANT                   P    SYS_C00411565

Solution

1
SELECT table_name FROM user_tables;
2
3
DESCRIBE tCours;
4
5
SELECT table_name, constraint_type AS type, constraint_name, search_condition
6
FROM   user_constraints
7
WHERE constraint_name NOT LIKE 'BIN$%'
8
ORDER BY table_name, constraint_type
9

Question

Initialiser la base avec les données suivantes :

  • Stéphane Crozat est un intervenant, poste 4287.

  • Il fait deux cours, Introduction et Modélisation, le 1 janvier et le 8 janvier 2001.

Indice

1
PKANNEE P TITRE           TYPE FKINTERVENANT   DEBUT   
2
------- - --------------- ---- --------------- ---------
3
   2001 1 Introduction    C    CROZAT          01-JAN-01 
4
   2001 2 Modélisation    TD   CROZAT          08-JAN-01 

Solution

1
INSERT INTO tIntervenant (pknom, prenom, poste)
2
VALUES 	('CROZAT', 'Stéphane', '4287');
3
4
INSERT INTO tCours (pkannee, pknum, titre, type, debut, fkintervenant) 
5
VALUES 	(2001, 1, 'Introduction','C', TO_DATE('01-01-2001','DD-MM-YYYY'), 'CROZAT');
6
7
INSERT INTO tCours (pkannee, pknum, titre, type, debut, fkintervenant) 
8
VALUES 	(2001, 2, 'Modélisation','TD', TO_DATE('08-01-2001','DD-MM-YYYY'), 'CROZAT');
9
10
SELECT * FROM tCours;

Question

Écrivez la requête SQL permettant de renvoyer pour chaque cours le jour de la semaine (lundi, mardi...) et le numéro de la semaine (1..53).

Indice

1
COURS DAY       WEEK
2
----- --------- ----
3
    1 monday    1    
4
    2 monday    2    

Solution

1
SELECT pknum AS cours, TO_CHAR(debut, 'fmday') AS day, TO_CHAR(debut, 'fmww') AS week FROM tcours;

Question

Écrivez la requête SQL permettant de renvoyer concaténés sur seule colonne le nom, le prénom et le poste entre parenthèse de chaque intervenant.

Indice

1
INTERVENANT
2
-------------------------------
3
STEPHANE CROZAT (4287)

Solution

1
SELECT prenom || ' ' || pknom || ' (' || poste || ')' AS intervenant FROM tIntervenant;

Question

Écrivez la requête SQL permettant de renvoyer la liste des cours avec leur type en toutes lettres : Cours, Travaux dirigés, Travaux pratiques.

Indice

1
COURS TYPE_LABEL      
2
----- -----------------
3
    1 Cours             
4
    2 Travaux dirigés   

Solution

1
SELECT pknum AS cours,
2
  CASE 
3
    WHEN type='C' THEN 'Cours' 
4
    WHEN type='TD' THEN 'Travaux dirigés'
5
    WHEN type='TP' THEN 'Travaux pratiques'
6
  END AS type_label
7
FROM tCours

Question

Écrivez le code SQL*Plus et la requête permettant de renvoyer toutes les informations de la table tCours sur un minimum de caractères.

Indice

1
   A N COURS           T  INTERVENANT     DEBUT   
2
---- - --------------- -- --------------- ---------
3
2001 1 Introduction    C  CROZAT          01-JAN-01 
4
2001 2 Modélisation    TD CROZAT          08-JAN-01 

Solution

1
COLUMN a FORMAT A4
2
COLUMN n FORMAT A1
3
COLUMN cours FORMAT A15
4
COLUMN t FORMAT A2
5
COLUMN intervenant FORMAT A15
6
7
SELECT 
8
  pkannee AS a,
9
  pknum AS n,
10
  titre AS cours,
11
  type AS T,
12
  fkintervenant AS intervenant,
13
  debut
14
FROM tCours;
15

PL/SQL sous Oracle

Pour la suite de l'exercice on introduira les données complémentaires suivantes dans la base de données.

1
INSERT INTO tIntervenant(pknom, prenom) VALUES ('JOUGLET', 'Antoine');

Question

Écrivez une fonction PL/SQL prenant en paramètre un intervenant et renvoyant la chaîne 'OUI' s'il intervient au moins une fois dans un cours, et 'NON' sinon.

Indice

1
PKNOM                I     
2
-------------------- ------
3
CROZAT               OUI
4
JOUGLET              NON

Indice

1
SELECT pknom, fIntervient(pknom) AS I FROM tIntervenant;

Indice

1
CREATE OR REPLACE FUNCTION fIntervient (...) 
2
  RETURN ...
3
IS
4
  ...;
5
BEGIN
6
  SELECT...
7
8
  IF...
9
END;
10
/

Solution

1
CREATE OR REPLACE FUNCTION fIntervient (pIntervenant VARCHAR2) 
2
  RETURN VARCHAR2
3
IS
4
  vNbInterventions NUMBER;
5
BEGIN
6
  SELECT COUNT(fkintervenant) INTO vNbInterventions
7
  FROM tCours 
8
  WHERE fkintervenant=pIntervenant;
9
10
  IF vNbInterventions > 0 THEN 
11
    RETURN 'OUI';
12
  ELSE
13
    RETURN 'NON';
14
  END IF;
15
END;
16
/
17
18
SELECT pknom, fIntervient(pknom) AS I FROM tIntervenant;

Question

Écrivez une procédure PL/SQL permettant d'afficher la liste de toutes les intervenants.

Indice

1
** Liste des intervenants **
2
-Stéphane Crozat
3
-Antoine Jouglet

Indice

1
SET SERVEROUTPUT ON;
2
BEGIN
3
  pAfficheIntervenants1;
4
END;
5
/

Indice

1
CREATE OR REPLACE PROCEDURE pAfficheIntervenants
2
IS
3
  CURSOR ...
4
  vNom ...
5
  vPrenom ...
6
BEGIN
7
  DBMS_OUTPUT.PUT_LINE...
8
  OPEN ...  
9
  LOOP
10
    FETCH...
11
    EXIT...
12
    DBMS_OUTPUT.PUT_LINE...
13
  END LOOP;
14
END;
15
/

Solution

1
CREATE OR REPLACE PROCEDURE pAfficheIntervenants
2
IS
3
  CURSOR cIntervenants IS
4
    SELECT pknom, prenom FROM tIntervenant;
5
  vNom tIntervenant.pknom%TYPE;
6
  vPrenom tIntervenant.prenom%TYPE;
7
BEGIN
8
  DBMS_OUTPUT.PUT_LINE('** Liste des intervenants **');
9
  OPEN cIntervenants;  
10
  LOOP
11
    FETCH cIntervenants INTO vNom, vPrenom;
12
    EXIT WHEN cIntervenants%NOTFOUND;
13
    DBMS_OUTPUT.PUT_LINE('-' || INITCAP(TRIM(vPrenom)) || ' ' || INITCAP(TRIM(vNom)));
14
  END LOOP;
15
END;
16
/
17
18
SET SERVEROUTPUT ON;
19
BEGIN
20
  pAfficheIntervenants1;
21
END;
22
/

Question

Écrivez un trigger permettant de gérer la redondance entre pkannee et debut. L'on souhaite le comportement suivant :

  • si l'année de début du cours ne correspond pas à pkanne, alors la date de début du cours est mise à NULL

  • on ajoute un message sur le sortie standard.

Indice

1
SET SERVEROUTPUT ON;
2
3
INSERT INTO tCours (pkannee, pknum, titre, type, fkIntervenant, debut)
4
VALUES ('2001', 3, 'SQL', 'C', 'CROZAT', TO_DATE('15-01-2001','DD-MM-YYYY'));
5
6
UPDATE tCours
7
SET debut=TO_DATE('15-01-2002','DD-MM-YYYY')
8
WHERE pknum=3;
9
10
SELECT pkannee, pknum, debut FROM tCours;
1
TRIGGER trCours compiled
2
1 rows inserted.
3
1 rows updated.
4
Inconsistency between debut and pkannee, debut set to null
5
6
PKAN PKNUM DEBUT   
7
---- ----- ---------
8
2001     1 01-JAN-01 
9
2001     2 08-JAN-01 
10
2001     3            

Indice

1
CREATE OR REPLACE TRIGGER trCours
2
BEFORE INSERT OR UPDATE OF debut ON tCours
3
FOR EACH ROW
4
DECLARE 
5
  vAnneeDebut INTEGER;
6
BEGIN
7
  vAnneeDebut := ...
8
  IF ...
9
END;
10
/
11

Solution

1
CREATE OR REPLACE TRIGGER trCours
2
BEFORE INSERT OR UPDATE OF debut ON tCours
3
FOR EACH ROW
4
DECLARE 
5
  vAnneeDebut INTEGER;
6
BEGIN
7
  vAnneeDebut := TO_NUMBER(TO_CHAR(:new.debut,'YYYY'));	
8
  IF NOT(vAnneeDebut = :new.pkannee) THEN
9
    :new.debut:=null;
10
    DBMS_OUTPUT.PUT_LINE('Inconsistency between debut and pkannee, debut set to null');
11
  END IF;
12
END;
13
/
14
15
SET SERVEROUTPUT ON;
16
17
INSERT INTO tCours (pkannee, pknum, titre, type, fkIntervenant, debut)
18
VALUES ('2001', 3, 'SQL', 'C', 'CROZAT', TO_DATE('15-01-2001','DD-MM-YYYY'));
19
20
UPDATE tCours
21
SET debut=TO_DATE('15-01-2002','DD-MM-YYYY')
22
WHERE pknum=3;
23
24
SELECT pkannee, pknum, debut FROM tCours;