Vous êtes sur la page 1sur 5

M1 Informatique – Année 2019-2020

Bases de données avancées


Épreuve écrite
J. Darmont (http://eric.univ-lyon2.fr/jdarmont/), 19/12/2019

Durée : 1h45 – Documents autorisés – Barème fourni à titre indicatif

Questions générales (3 points)

1. Soit la table PRODUIT(id, nom, description, categorie, prix). Pour charger en mémoire le résultat de la
requête SELECT * FROM PRODUIT WHERE categorie = ‘Téléphone’, quel mécanisme faut-il utiliser  :
SELECT INTO variable ou bien curseur ? Justifier.

2. Un curseur paramétré est-il implicite (non lié) ou explicite (lié) ? Justifier.

3. Quelle caractéristique permet aux données semi-structurées de ne pas avoir de schéma ?

PL/pgSQL (10 points)

Soit la base de données « Los Surfers Muertos » dont le schéma relationnel est donné ci-dessous.

SURFEUR (NumSurfeur, Surnom, DateNaiss, Sexe)


SPOT (CodeSpot, NomSpot, Localisation)
COMPET (Surfeur#, Spot#, Annee, Points, Gain)

1. Créer un type composite (enregistrement) de nom tResultat, constitué de deux champs  : libelle (chaîne de
caractères) et valeur (nombre).

2. Écrire une fonction de nom gainsHF() qui renvoie la moyenne des gains des surfeurs (H) et des surfeuses
(F), respectivement.

3. Écrire une fonction de nom listeCompet() qui renvoie le nom du spot, l’année et le nombre de points
d’un∙e surfeur∙se dont le surnom est passé en paramètre à la fonction.

4. Soit la table TABLEAU (Année, NumSurfeur#, Surnom, totalPoints) qui récapitule le nombre de points
accumulés chaque année par chaque surfeur, avec un tri croissant sur l’année et décroissant sur la somme
des points. Écrire un déclencheur de nom trigTableau qui, pour toute mise à jour de la table COMPET,
recalcule intégralement le contenu de la table TABLEAU. De plus, si l’une des valeurs de Points dans la
table COMPET n’est pas renseignée, lever une exception qui interrompt le traitement.

XQuery (7 points)

Soient les trois documents XML articles.xml (articles de presse), images.xml (photos) et inventaire.xml (liste
de bâtiments) liés au patrimoine industriel de la région lilloise (projet de recherche TECTONIQ 1). La structure
de ces documents XML est donnée ci-contre.

+ Cardinalité 1 à plusieurs
* Cardinalité 0 à plusieurs
? Cardinalité 0 ou 1

1 http://tectoniq.meshs.fr/

M1 Informatique – Bases de données avancées – Épreuve écrite 1/2


articles.xml images.xml inventaire.xml
corpus liste inventaire
document+ enregistrement+ enregistrement+
description code-img code-bat
auteur+ description description
titre titre proprietaire
sous-titre? date addresse
date mot-cle* type-batiment
langue mot-cle-geo* type-toit
texte origine etages
references condition
ref-img*
ref-bat*
evaluation
note

Formuler à l’aide du langage XQuery les requêtes suivantes (utiliser, de la syntaxe XPath ou FLWOR, la
plus appropriée).

1. Adresses distinctes des bâtiments.

2. Articles qui contiennent un sous-titre.

3. Code des photos prises avant l’an 2000 et dont la description contient le mot-clé « Usine ».

4. Information concernant les images au format suivant : <image code="C" statut="S" /> ; où C est
le code-img de la photo et S est égal à « ancienne » si la photo a été prise avant l’an 2000, « récente »
sinon.

5. Pour chaque image, donner son titre (dans un élément image) et le titre de l’article dans lequel elle
apparaît (dans un élément article).

6. Nombre moyen d’étages par adresse.

7. Nombre total de références (d’images et de bâtiments) par article (indiquer le titre).

M1 Informatique – Bases de données avancées – Épreuve écrite 2/2


Correction Questions générales

1. La requête pouvant retourner plusieurs n-uplets, il faut utiliser un curseur.

2. Un curseur paramétré est toujours explicite. L’ouverture du curseur permet notamment la transmission
des paramètres.

3. Les données semi-structurées ne nécessitent pas obligatoirement de schéma car elles sont
autodescriptives.

Correction PL/pgSQL

-- 1
create type tResultat as (
libelle varchar,
valeur numeric
);

-- 2
create or replace function gainsHF() returns setof tResultat as $$
declare
res tResultat;
begin
res.libelle := 'Surfeurs';
select avg(gain) into res.valeur from COMPET c, SURFEUR s
where c.Surfeur = s.NumSurfeur and sexe = 'H';
return next res;
res.libelle := 'Surfeuses';
select avg(gain) into res.valeur from COMPET c, SURFEUR s
where c.Surfeur = s.NumSurfeur and sexe = 'F';
return next res;
return;
end
$$ language plpgsql;

-- 3
create type tCompet as (
spot varchar,
annee numeric,
points numeric
);

create or replace function listeCompet(nom varchar) returns setof tCompet as $$


declare
c tCompet;
begin
for c in select NomSpot, Annee, Points from COMPET, SURFEUR s, SPOT t
where COMPET.Surfeur = s.NumSurfeur and COMPET.Spot = t.CodeSpot
and surnom = nom
loop
return next c;
end loop;
return;
end
$$ language plpgsql;

M1 Informatique – Bases de données avancées – Épreuve écrite 3/2


-- 4
create or replace function trigTableau() returns trigger as $$
declare
n integer := 0;
t TABLEAU%ROWTYPE;
begin
-- Remise à zéro du tableau
delete from TABLEAU;

-- Test sur les valeurs de Points


select count(*) into n from COMPET where Points is null;
if n > 0 then
raise exception 'Il manque des valeurs de points.';
end if;

-- Remplissage du tableau
for t in select Annee, NumSurfeur, Surnom, sum(Points) as totalPoints
from COMPET c, SURFEUR s where c.Surfeur = s.NumSurfeur
group by Annee, NumSurfeur, Surnom order by Annee, totalPoints
DESC
loop
insert into TABLEAU VALUES(t.Annee, t.NumSurfeur, t.Surnom,
t.totalPoints);
end loop;
return NEW;
end
$$ language plpgsql;

create trigger trigTableau


after insert or delete or update
on COMPET
for each statement
execute procedure trigTableau();

Correction XQuery

(: 1 :)
distinct-values(//adresse)

(: 2 :)
//document[//sous-titre]

(: 3 :)
/liste/enregistrement[year-from-date(description/date) < 2000
and description/mot-cle = "Usine"]/code-
img

(: 4 :)
for $i in /liste/enregistrement
return if (year-from-date($i/description/date) < 2000)
then <image code="{data($i/code-img)}" statut="ancienne" />
else <image code="{data($i/code-img)}" statut="récente" />

(: 5 :)
for $i in /liste/enregistrement, for $i in /liste/enregistrement,
$a in //document $a in //document[$i/code-img =
where $a//ref-img = $i/code-img references/ref-img]
return return
<resultat> <resultat>
<image>{data($i//titre)}</image> <image>{data($i//titre)}</image>
<article>{data($a//titre)}</article> <article>{data($a//titre)}</article>
</resultat> </resultat>

M1 Informatique – Bases de données avancées – Épreuve écrite 4/2


(: 6 :)
for $b in /inventaire//description
group by $a := $b/adresse
return <batiment adresse="{$a}" nb-etages="{avg($b/etages)}" />

(: 7 :)
for $a in //document
group by $t := $a//titre
return <article titre="{$t}"
nbreferences="{count($a//ref-img) + count($a//ref-bat)}" />

M1 Informatique – Bases de données avancées – Épreuve écrite 5/2

Vous aimerez peut-être aussi