You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

558 lines
20 KiB

-- 2. Ecrire un bloc PL/pgSQL anonyme qui affiche
DO $$
DECLARE
a numeric := 0;
b numeric := 1;
c numeric;
i integer := 0;
BEGIN
WHILE i<10 LOOP
c=a+b;
RAISE NOTICE 'a=% b=% c=%', a, b, c;
a=b;
b=c;
i=i+1;
END LOOP;
END;
$$;
-- 3. Faire la meme mais en fonction pgSQL
CREATE OR REPLACE FUNCTION fibonacci(n integer) RETURNS SETOF integer AS $$
DECLARE
a numeric := 0;
b numeric := 1;
c numeric;
i integer := 0;
BEGIN
WHILE i<(n-1) LOOP
c=a+b;
-- RAISE NOTICE 'a=% b=% c=%', a, b, c;
a=b;
b=c;
i=i+1;
RETURN NEXT c;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- 4. Appel de la fonction avec comme parametre 0, 1, 2, 10
SELECT fibonacci(0);
SELECT * FROM fibonacci(1);
SELECT * FROM fibonacci(2);
SELECT * FROM fibonacci(10);
-- fibonacci
-- -----------
-- (0 ligne)
-- fibonacci
-- -----------
-- (0 ligne)
-- fibonacci
-- -----------
-- 1
-- (1 ligne)
-- fibonacci
-- -----------
-- 1
-- 2
-- 3
-- 5
-- 8
-- 13
-- 21
-- 34
-- 55
-- (9 lignes)
-- 5. Ecrire une fonction en plpgsql nb_athletes qui retourn le nombre d'athlètes d'un pays dont le code est passé en paramètre
CREATE OR REPLACE FUNCTION nb_athletes(pays_code character varying) RETURNS integer AS $$
DECLARE
nb_athletes integer;
BEGIN
SELECT COUNT(*) INTO nb_athletes FROM athlete WHERE pays = pays_code;
RETURN nb_athletes;
END;
$$ LANGUAGE plpgsql;
-- 6. Utiliser la fonction précédente pour calculer le nombre d'athlèthes français
SELECT nb_athletes('FRA');
-- nb_athletes
-- -------------
-- 396
-- (1 ligne)
-- 7. Ecrire une requete sql utilisant la fonction nb_athletes pour afficher le code et le nom de tous les pays ayant plus d'athlètes que la France
SELECT pays, nom
FROM pays
WHERE nb_athletes(pays.code) > nb_athletes('FRA');
-- pays | nom
-- ------------------------------------+----------------------------
-- (AUS,Australia) | Australia
-- (USA,"United States of America") | United States of America
-- (GER,Germany) | Germany
-- (JPN,Japan) | Japan
-- (CHN,"People's Republic of China") | People's Republic of China
-- (5 lignes)
-- 8. Ecrire une fonction en pgpsql epr qui prend deux paramètres (le nom d'une discipline et une date) et qui retourne les epreuves (code et nom) de cette discipline ayant lieu à la date donnée
CREATE OR REPLACE FUNCTION epr(discipline varchar, date date) RETURNS SETOF epreuve AS $$
DECLARE
epreuve epreuve;
BEGIN
FOR epreuve IN SELECT *
FROM epreuve e, discipline d
WHERE e.discipl = d.code AND e.dateE = date LOOP
RETURN NEXT epreuve;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- %TYPE pour recuperer le type de la colonne
-- 9. Utiliser la fonction epr pour afficher les noms des epreuves d'athlètisme ('Athletics') ayant lieu le 3 août 2021
SELECT epr('Athletics', '2021-08-03');
-- epr
-- ----------------------------------------------------------------------
-- (E206,GAR,"Men's Horizontal Bar",2021-08-03)
-- (E207,GAR,"Men's Parallel Bars",2021-08-03)
-- (E208,GAR,"Women's Balance Beam",2021-08-03)
-- (E209,ATH,"Men's 400m Hurdles",2021-08-03)
-- (E210,ATH,"Men's Pole Vault",2021-08-03)
-- (E211,ATH,"Women's 200m",2021-08-03)
-- (E212,ATH,"Women's 800m",2021-08-03)
-- (E213,ATH,"Women's Hammer Throw",2021-08-03)
-- (E214,ATH,"Women's Long Jump",2021-08-03)
-- (E215,BOX,"Men's Feather (52-57kg)",2021-08-03)
-- (E216,BOX,"Men's Heavy (81-91kg)",2021-08-03)
-- (E217,BOX,"Men's Welter (63-69kg)",2021-08-03)
-- (E218,BOX,"Women's Feather (54-57kg)",2021-08-03)
-- (E219,CSP,"Men's Canoe Double 1000m",2021-08-03)
-- (E220,CSP,"Men's Kayak Single 1000m",2021-08-03)
-- (E221,CSP,"Women's Kayak Double 500m",2021-08-03)
-- (E222,CSP,"Women's Kayak Single 200m",2021-08-03)
-- (E223,CTR,"Men's Team Sprint",2021-08-03)
-- (E224,CTR,"Women's Team Pursuit",2021-08-03)
-- (E225,DIV,"Men's 3m Springboard",2021-08-03)
-- (E226,SAL,"Men's One Person Dinghy (Heavyweight) - Finn",2021-08-03)
-- (E227,SAL,"Men's Skiff - 49er",2021-08-03)
-- (E228,SAL,"Mixed Multihull - Nacra 17 Foiling",2021-08-03)
-- (E229,SAL,"Women's Skiff - 49er FX",2021-08-03)
-- (E230,WLF,"Men's 109kg",2021-08-03)
-- (E231,WRE,"Men's Greco-Roman 77kg",2021-08-03)
-- (E232,WRE,"Men's Greco-Roman 97kg",2021-08-03)
-- (E233,WRE,"Women's Freestyle 68kg",2021-08-03)
-- (28 lignes)
-- 10. Le mauvais temps empêche la tenue de compétition en exterieur. Utiliser la fonction epr pour décaler d'un jour toutes les epreuves d'équitation ('Equestrian') ayant lieu le 2 août 2021
SELECT epr('Equestrian', '2021-08-02');
-- epr
-- ---------------------------------------------------
-- (E186,GAR,"Men's Rings",2021-08-02)
-- (E187,GAR,"Men's Vault",2021-08-02)
-- (E188,GAR,"Women's Floor Exercise",2021-08-02)
-- (E189,ATH,"Men's 3000m Steeplechase",2021-08-02)
-- (E190,ATH,"Men's Long Jump",2021-08-02)
-- (E191,ATH,"Women's 100m Hurdles",2021-08-02)
-- (E192,ATH,"Women's 5000m",2021-08-02)
-- (E193,ATH,"Women's Discus Throw",2021-08-02)
-- (E194,BDM,"Men's Singles",2021-08-02)
-- (E195,BDM,"Women's Doubles",2021-08-02)
-- (E196,CTR,"Women's Team Sprint",2021-08-02)
-- (E197,EQU,"Eventing Individual",2021-08-02)
-- (E198,EQU,"Eventing Team",2021-08-02)
-- (E199,SHO,"25m Rapid Fire Pistol Men",2021-08-02)
-- (E200,SHO,"50m Rifle 3 Positions Men",2021-08-02)
-- (E201,WLF,"Women's +87kg",2021-08-02)
-- (E202,WLF,"Women's 87kg",2021-08-02)
-- (E203,WRE,"Men's Greco-Roman 130kg",2021-08-02)
-- (E204,WRE,"Men's Greco-Roman 60kg",2021-08-02)
-- (E205,WRE,"Women's Freestyle 76kg",2021-08-02)
-- (20 lignes)
-- UPDATE 0
-- 11. Ecrire une fonction pratique qui retourne le nom de la discipline pratiqué par un athlète dont on passe le code en paramètre
CREATE OR REPLACE FUNCTION pratique(code_athlete athlete.code%TYPE) RETURNS discipline.nom%TYPE AS $$
DECLARE
res discipline.nom%TYPE;
BEGIN
SELECT d.nom INTO STRICT res FROM pratiquer p
INNER JOIN discipline d ON d.code = p.discipl
WHERE p.athlete = code_athlete;
return res;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
RAISE EXCEPTION 'L''athlète % pratique plusieurs sports.', code_athlete;
WHEN NO_DATA_FOUND THEN
RAISE EXCEPTION 'Athlète % inconnu.', code_athlete;
END;
$$ LANGUAGE plpgsql;
-- ? 12. Utiliser la fonction pratique pour trouver le sport pratiqué par Earvin NGAPETH
SELECT pratique(
(
SELECT code FROM athlete WHERE prenom = 'Earvin' AND nom = upper('Ngapeth')
)
);
-- pratique
-- ------------
-- Volleyball
-- (1 ligne)
-- ? 13. Meme question pour l'athlete Lotte KOPECKY
SELECT pratique(
(
SELECT code FROM athlete WHERE prenom = 'Lotte' AND nom = upper('Kopecky')
)
);
-- ERREUR: L'athlète A05315 pratique plusieurs sports.
-- CONTEXTE : fonction PL/pgSQL pratique(character), ligne 11 à RAISE
-- ? 14. Meme question pour l'thlete de code 'B01' (qui n'existe pas)
SELECT pratique('B01');
-- ASTUCE : N'a pas pu choisir un meilleur candidat dans les fonctions. Vous pourriez
-- avoir besoin d'ajouter des conversions explicites de type.
-- ? 15 Ecrire une fonction medailles calculant le pourcentage d'athlèthes médaillés parmis ceux du pays passé en paramètre
CREATE OR REPLACE FUNCTION medailles(code_pays pays.code%TYPE)
RETURNS FLOAT AS $$
DECLARE
total_athletes INT;
athletes_medailles INT;
BEGIN
SELECT COUNT(*) INTO total_athletes
FROM athlete
WHERE pays = code_pays;
IF total_athletes = 0 THEN
RAISE EXCEPTION 'Le pays [%] % n''a pas d''athlète.', code_pays, (SELECT nom FROM pays WHERE code = code_pays);
END IF;
SELECT COUNT(DISTINCT r.athlete) INTO athletes_medailles
FROM resultat r
INNER JOIN athlete a ON a.code = r.athlete
WHERE a.pays = code_pays;
return athletes_medailles::FLOAT / total_athletes;
END;
$$ LANGUAGE plpgsql;
-- ? 16. Tester votre fonction medailles avec la France
SELECT medailles(
(
SELECT code FROM pays WHERE nom = 'France'
)
);
-- medailles
-- --------------------
-- 0.3282828282828283
-- (1 ligne)
-- ? 17. Même question avec l'URSS
SELECT medailles(
(
SELECT code FROM pays WHERE nom = 'URSS'
)
);
-- ERREUR: Le pays [URS] URSS n'a pas d'athlète.
-- CONTEXTE : fonction PL/pgSQL medailles(character), ligne 11 à RAISE
-- ? 18. Utiliser la fonction medailles pour afficher tous les pays (nom et pourcentage de médaillés). avec les pays les plus détaillés (proportionellement parlant) en premier. Le pourcentage de médaillés devra avoir au plus 2décimales.
SELECT p.nom, ROUND((medailles(p.code) * 100)::numeric, 2) medailles
FROM resultat r
INNER JOIN athlete a ON a.code = r.athlete
INNER JOIN pays p ON p.code = a.pays
GROUP BY p.code
ORDER BY 2 DESC;
-- nom | medailles
-- ----------------------------+-----------
-- Fiji | 81.25
-- San Marino | 60.00
-- Bermuda | 50.00
-- Dominican Republic | 46.97
-- United States of America | 40.60
-- Serbia | 40.23
-- ROC | 37.54
-- France | 32.83
-- Botswana | 28.57
-- Great Britain | 28.32
-- People's Republic of China | 27.08
-- Denmark | 26.85
-- New Zealand | 26.75
-- Hungary | 26.74
-- Qatar | 25.00
-- Norway | 24.73
-- Bulgaria | 23.81
-- Armenia | 23.53
-- Chinese Taipei | 23.53
-- Sweden | 23.53
-- Cuba | 23.19
-- Jamaica | 22.95
-- Georgia | 22.86
-- Argentina | 22.75
-- Netherlands | 21.91
-- Indonesia | 21.43
-- Philippines | 21.05
-- Spain | 20.83
-- Australia | 20.25
-- Belgium | 20.00
-- Greece | 19.51
-- India | 19.05
-- Kyrgyzstan | 18.75
-- Japan | 18.57
-- Canada | 18.39
-- Croatia | 18.33
-- Kosovo | 18.18
-- Italy | 17.11
-- Slovakia | 17.07
-- Germany | 17.07
-- Brazil | 16.93
-- Syrian Arab Republic | 16.67
-- Grenada | 16.67
-- Mexico | 16.67
-- Ukraine | 16.34
-- 94 lignes
-- ? 19. Ecrire une fonction ageMoy qui calcule et retourne l'âge moyen des athlètes d'un pays dont le code est passé en paramètres
CREATE OR REPLACE FUNCTION ageMoy_V1(code_pays pays.code%TYPE)
RETURNS FLOAT AS $$
BEGIN
return (
SELECT AVG(CURRENT_DATE - dateNaiss) / 365.2422
FROM athlete
WHERE pays = code_pays
);
END;
$$ LANGUAGE plpgsql;
-- ? 20. Modifier la fonction ageMoy pour qu'elle retourn 0 si aucun athlète ne concourt pour le pays ou si on ne connait l'âge d'aucun de ses athlètes
DROP FUNCTION IF EXISTS ageMoy_V2;
CREATE OR REPLACE FUNCTION ageMoy_V2(code_pays pays.code%TYPE)
RETURNS FLOAT AS $$
DECLARE
i INT;
fin INT;
total INT := 0;
nb INT := 0;
date_naiss athlete.dateNaiss%TYPE;
BEGIN
-- Oui.
SELECT SUBSTR(MIN(code), 2)::int INTO i FROM athlete WHERE pays = code_pays;
SELECT SUBSTR(MAX(code), 2)::int INTO fin FROM athlete WHERE pays = code_pays;
if i IS NULL then
return 0;
end if;
-- Teste pour chaque code possible
while i <= fin loop
SELECT dateNaiss INTO date_naiss FROM athlete WHERE code = to_char(i, 'FMA00000');
if date_naiss IS NOT NULL then
total = (CURRENT_DATE - date_naiss) + total;
nb = nb + 1;
end if;
i = i + 1;
end loop;
if nb = 0 then
return 0;
end if;
return total::FLOAT / nb / 365.2422;
END;
$$ LANGUAGE plpgsql;
-- ? 21. Utiliser cette fonction pour trouver le pays dont les thlètes sont en moyenne les plus jeunes
-- ? 22. Même question pour le pays dont les athlètes sont en moyenne les plus jeunes
CREATE OR REPLACE FUNCTION ageMoy_V1(code_pays pays.code%TYPE)
RETURNS FLOAT AS $$
BEGIN
return (
SELECT COALESCE(AVG(CURRENT_DATE - dateNaiss), 0) / 365.2422
FROM athlete
WHERE pays = code_pays AND dateNaiss IS NOT NULL
);
END;
$$ LANGUAGE plpgsql;
SELECT ageMoy_V1('') v1, ageMoy_V2('') v2;
-- v1 | v2
-- ----+----
-- 0 | 0
-- (1 ligne)
WITH age_moyen AS (
SELECT nom, ageMoy_V1(code) AS age_moyen FROM pays
) SELECT nom, age_moyen
FROM age_moyen
ORDER BY age_moyen DESC
LIMIT 1;
-- nom | age_moyen
-- ----------------------+-------------------
-- United Arab Emirates | 34.15103731167976
-- (1 ligne)
WITH age_moyen AS (
SELECT nom, ageMoy_V1(code) AS age_moyen FROM pays
) SELECT nom, age_moyen
FROM age_moyen
WHERE age_moyen != 0
ORDER BY age_moyen
LIMIT 1;
-- nom | age_moyen
-- -------------------------------+--------------------
-- St Vincent and the Grenadines | 21.159475365478944
-- (1 ligne)
-- ? 23. Creer une fonction gagner qui prend en paramètre un code d'athlète et une couleur de médaille ('Or', 'Argent' ou 'Bronze') et qui retourne le nombre de médailles de cette couleur gagnées par cet athlète
CREATE OR REPLACE FUNCTION gagner(code_athlete athlete.code%TYPE, couleur_medaille medaille.couleur%TYPE)
RETURNS INT AS $$
BEGIN
return (
SELECT COUNT(*) FROM resultat WHERE athlete = code_athlete AND medaille = (
SELECT place FROM medaille WHERE couleur = couleur_medaille
)
);
END;
$$ LANGUAGE plpgsql;
-- ? 24. Tester votre fonction en affichant le nombre de médailles d'or, d'argent et de bronze gagnées par l'athlète Teddy RINER
SELECT gagner(
(SELECT code FROM athlete WHERE prenom = 'Teddy' AND nom = 'RINER'),
'Or'
) medailles_or, gagner(
(SELECT code FROM athlete WHERE prenom = 'Teddy' AND nom = 'RINER'),
'Argent'
) medailles_argent, gagner(
(SELECT code FROM athlete WHERE prenom = 'Teddy' AND nom = 'RINER'),
'Bronze'
) medailles_bronze;
-- medailles_or | medailles_argent | medailles_bronze
-- --------------+------------------+------------------
-- 1 | 0 | 1
-- (1 ligne)
-- ? 25. Creer une table Resultat_FR(code, nom, prenom, dateNaiss, nb_or, nb_argent, nb_bronze) qui servira pour contenir les résultats des athlètes français
CREATE TABLE IF NOT EXISTS resultat_fr (
code CHAR(6) PRIMARY KEY REFERENCES athlete(code),
nom VARCHAR(40) NOT NULL,
prenom VARCHAR(40) NOT NULL,
dateNaiss DATE,
nb_or INT DEFAULT 0,
nb_argent INT DEFAULT 0,
nb_bronze INT DEFAULT 0
);
-- ? 26. Remplir la table Resultat_FR avec une requete INSERT
INSERT INTO resultat_fr
SELECT code, nom, prenom, dateNaiss, gagner(code, 'Or'), gagner(code, 'Argent'), gagner(code, 'Bronze')
FROM athlete
WHERE pays = (SELECT code FROM pays WHERE nom = 'France');
-- INSERT 0 396
-- ? 27. Afficher les resultats des athlètes fraçais en les ordonnant en fonction du nombre total de médailles gagnées (les gagnants du plus grand nombre de médailles en premier), puis par date de naissance (les athlètes les plus agés en premier)
SELECT *
FROM resultat_fr
ORDER BY (nb_or + nb_argent + nb_bronze) DESC, dateNaiss;
-- code | nom | prenom | datenaiss | nb_or | nb_argent | nb_bronze
-- --------+---------------------+--------------------+------------+-------+-----------+-----------
-- A08619 | RINER | Teddy | 1989-04-07 | 1 | 0 | 1
-- A00129 | AGBEGNENOU | Clarisse | 1992-10-25 | 2 | 0 | 0
-- A06252 | MALONGA | Madeleine | 1993-12-25 | 1 | 1 | 0
-- A01407 | BUCHARD | Amandine | 1995-07-12 | 1 | 1 | 0
-- A01390 | BRUNET | Manon | 1996-02-07 | 0 | 1 | 1
-- A02151 | CYSIQUE | Sarah Leonie | 1998-07-06 | 1 | 1 | 0
-- A02474 | DICKO | Romane | 1999-09-30 | 1 | 0 | 1
-- A05542 | LAGHOUAG | Karim Florent | 1975-08-04 | 0 | 0 | 1
-- A10338 | TOUZAINT | Nicolas | 1980-05-10 | 0 | 0 | 1
-- A03395 | GENTY | Yann | 1981-12-26 | 1 | 0 | 0
-- A05650 | le PECHOUX | Erwann | 1982-01-13 | 1 | 0 | 0
-- A03762 | GUIGOU | Michael | 1982-01-28 | 1 | 0 | 0
-- A03801 | GUYART | Astrid | 1983-03-17 | 0 | 1 | 0
-- A04842 | KARABATIC | Nikola | 1984-04-11 | 1 | 0 | 0
-- A00006 | ABALO | Luc | 1984-09-06 | 1 | 0 | 0
-- A08096 | PICON | Charline | 1984-12-23 | 0 | 1 | 0
-- A05666 | LECOINTRE | Camille | 1985-02-25 | 0 | 0 | 1
-- A09538 | SIX | Christopher | 1985-12-12 | 0 | 0 | 1
-- A04242 | HORTA | Fanny | 1986-01-22 | 0 | 1 | 0
-- A05786 | LEYNAUD | Amandine | 1986-05-02 | 1 | 0 | 0
-- A01702 | CHAINE | Guillaume | 1986-10-24 | 1 | 0 | 0
-- A03406 | GERARD | Vincent | 1986-12-16 | 1 | 0 | 0
-- A01964 | CLERGET | Axel | 1987-02-28 | 1 | 0 | 0
-- A05532 | LACRABERE | Alexandra | 1987-04-27 | 1 | 0 | 0
-- A02279 | de COLO | Nando | 1987-06-23 | 0 | 1 | 0
-- A03725 | GRUDA | Sandrine | 1987-06-25 | 0 | 0 | 1
-- A02203 | DANCETTE | Blandine | 1988-02-14 | 1 | 0 | 0
-- A04841 | KARABATIC | Luka | 1988-04-19 | 1 | 0 | 0
-- A06873 | MIYEM | Endene | 1988-05-15 | 0 | 0 | 1
-- A06706 | MERTINE | Julien | 1988-06-25 | 1 | 0 | 0
-- A02719 | EDWIGE | Beatrice | 1988-10-03 | 1 | 0 | 0
-- A00863 | BATUM | Nicolas | 1988-12-14 | 0 | 1 | 0
-- A06746 | MICHEL | Sarah | 1989-01-10 | 0 | 0 | 1
-- A04110 | HEURTEL | Thomas | 1989-04-10 | 0 | 1 | 0
-- A08133 | PINEAU | Allison | 1989-05-02 | 1 | 0 | 0
-- A06053 | LUIS | Vincent | 1989-06-27 | 0 | 0 | 1
-- A02223 | DARLEUX | Cleopatre | 1989-07-01 | 1 | 0 | 0
-- A05645 | le BLOUCH | Kilian | 1989-10-07 | 1 | 0 | 0
-- A10287 | TONIUTTI | Benjamin | 1989-10-30 | 1 | 0 | 0
-- A07942 | PELLE | Chloe | 1989-11-14 | 0 | 1 | 0
-- A00982 | BERDER | Cecilia | 1989-12-13 | 0 | 1 | 0
-- A01912 | CIAK | Helena | 1989-12-15 | 0 | 0 | 1
-- A00223 | ALBICY | Andrew | 1990-03-21 | 0 | 1 | 0
-- A00434 | ANDRODIAS | Matthieu | 1990-06-11 | 1 | 0 | 0
-- A03667 | GREBENNIKOV | Jenia | 1990-08-13 | 1 | 0 | 0
-- 396 lignes