\! clear -- -- ? 1 - Écrire une fonction qui pour un match donné calcule le nombre de rebonds -- -- ? pris par les joueurs qui n’ont pas débuté la rencontre. Proposez deux versions, -- -- ? une utilisant les fonctions d’agrégation et une autre utilisant un curseur mais aucune fonction d’agrégation. -- CREATE OR REPLACE FUNCTION calcul_rebonds(match Game.id%TYPE) RETURNS integer AS $$ -- DECLARE -- sumRebounds integer; -- BEGIN -- SELECT sum(gd.rebounds) INTO sumRebounds -- FROM GameDetail gd, Game g -- WHERE g.id = match AND gd.idGame = g.id AND gd.startPosition is NULL; -- RETURN sumRebounds; -- END; -- $$ LANGUAGE plpgsql; -- SELECT calcul_rebonds('22100979'); -- -- CREATE FUNCTION -- -- calcul_rebonds -- -- ---------------- -- -- 32 -- -- (1 row) -- CREATE OR REPLACE FUNCTION calcul_rebonds_curs(match Game.id%TYPE) RETURNS GameDetail.rebounds%TYPE AS $$ -- DECLARE -- sumRebounds GameDetail.rebounds%TYPE := 0; -- rbs GameDetail.rebounds%TYPE := 0; -- curs cursor FOR SELECT rebounds -- FROM GameDetail -- WHERE idGame = match AND startPosition is NULL AND rebounds is NOT NULL; -- BEGIN -- OPEN curs; -- FETCH curs INTO rbs; -- WHILE FOUND LOOP -- sumRebounds = sumRebounds + rbs; -- FETCH curs INTO rbs; -- END LOOP; -- CLOSE curs; -- RETURN sumRebounds; -- END; -- $$ LANGUAGE plpgsql; -- SELECT calcul_rebonds_curs('22100979'); -- -- CREATE FUNCTION -- -- calcul_rebonds_curs -- -- --------------------- -- -- 32 -- -- (1 row) -- -- ? 2 - Vérifier que vos deux versions retournent les mêmes résultats en affichant le nombre total de rebonds -- -- ? pris par les joueurs n’ayant pas débuté la rencontre pour tous les matchs ayant eu lieu le 12 mars 2022. -- SELECT calcul_rebonds(id) -- FROM Game -- WHERE dateGame = '2022-03-12'; -- -- calcul_rebonds -- -- ---------------- -- -- 39 -- -- 20 -- -- 43 -- -- 40 -- -- 41 -- -- 25 -- -- 24 -- -- (7 rows) -- SELECT calcul_rebonds_curs(id) -- FROM Game -- WHERE dateGame = '2022-03-12'; -- -- calcul_rebonds_curs -- -- --------------------- -- -- 39 -- -- 20 -- -- 43 -- -- 40 -- -- 41 -- -- 25 -- -- 24 -- -- (7 rows) -- -- ? 3 - Écrire une fonction qui calcule la même chose mais pour les joueurs ayant débuté la rencontre, -- -- ? autrement dit qui calcule, pour un match donné, le nombre de rebonds pris par les joueurs ayant débuté la rencontre. -- CREATE OR REPLACE FUNCTION calcul_rebonds_t(match Game.id%TYPE) RETURNS integer AS $$ -- DECLARE -- sumRebounds integer; -- BEGIN -- SELECT sum(gd.rebounds) INTO sumRebounds -- FROM GameDetail gd, Game g -- WHERE g.id = match AND gd.idGame = g.id AND gd.startPosition is NOT NULL; -- IF sumRebounds is NULL THEN -- RETURN 0; -- END IF; -- RETURN sumRebounds; -- END; -- $$ LANGUAGE plpgsql; -- SELECT calcul_rebonds_t('22100979'); -- -- CREATE FUNCTION -- -- calcul_rebonds_t -- -- ------------------ -- -- 57 -- -- (1 row) -- CREATE OR REPLACE FUNCTION calcul_rebonds_curs_t(match Game.id%TYPE) RETURNS GameDetail.rebounds%TYPE AS $$ -- DECLARE -- sumRebounds GameDetail.rebounds%TYPE := 0; -- rbs GameDetail.rebounds%TYPE := 0; -- curs cursor FOR SELECT rebounds -- FROM GameDetail -- WHERE idGame = match AND startPosition is NOT NULL AND rebounds is NOT NULL; -- BEGIN -- OPEN curs; -- FETCH curs INTO rbs; -- WHILE FOUND LOOP -- sumRebounds = sumRebounds + rbs; -- FETCH curs INTO rbs; -- END LOOP; -- CLOSE curs; -- RETURN sumRebounds; -- END; -- $$ LANGUAGE plpgsql; -- SELECT calcul_rebonds_curs_t('22100979'); -- -- CREATE FUNCTION -- -- calcul_rebonds_curs_t -- -- ----------------------- -- -- 57 -- -- (1 row) -- SELECT calcul_rebonds_t('10300004'); -- SELECT calcul_rebonds_curs_t('10300004'); -- -- ? 4 - Trouver le match (abréviation des équipes et date) pendant lequel les joueurs -- -- ? ayant débuté la rencontre ont réalisé le plus de rebonds. -- SELECT t1.abbreviation, t2.abbreviation, g.dateGame, calcul_rebonds_t(g.id) -- FROM Game g, Team t1, Team t2 -- WHERE g.idHomeTeam = t1.id AND g.idVisitorTeam = t2.id AND calcul_rebonds_t(g.id) = (SELECT max(calcul_rebonds_t(id)) -- FROM Game); -- -- abbreviation | abbreviation | dategame | calcul_rebonds_t -- -- --------------+--------------+------------+------------------ -- -- POR | DEN | 2019-05-03 | 101 -- -- (1 row) -- -- ? 5 - Y a t’il des matchs pour lesquels les données sur les rebonds sont incohérentes? -- -- ? Vérifier en comparant les valeurs obtenus grâce aux fonctions précédentes avec les valeurs contenues dans la table Game. -- -- ! SELECT t1.abbreviation, t2.abbreviation, g.dateGame, (calcul_rebonds_t(g.id) + calcul_rebonds(g.id)) as fct, g.reboundsHome, g.reboundsAway -- -- ! FROM Game g, Team t1, Team t2 -- -- ! WHERE g.idHomeTeam = t1.id AND g.idVisitorTeam = t2.id AND calcul_rebonds_t(g.id) = (SELECT max(calcul_rebonds_t(id)) -- -- ! FROM Game); -- -- ? 6 - Écrire une fonction qui pour un match et une équipe donnée calcule le total des points des joueurs de cet équipe pendant le match, -- -- ? à partir des données contenues dans la table GameDetail. -- CREATE OR REPLACE FUNCTION PtsTotJoueur(match Game.id%TYPE, team Team.id%TYPE) -- RETURNS integer as $$ -- DECLARE total integer; -- BEGIN -- SELECT sum(points) INTO total -- FROM GameDetail -- WHERE idTeam = team AND idGame = match AND points IS NOT NULL; -- IF total is NULL THEN -- RETURN 0; -- END IF; -- RETURN total; -- END; -- $$ LANGUAGE plpgsql; -- SELECT PtsTotJoueur('22101006','1610612741'); -- -- ? 7 - Utiliser cette fonction pour vérifier si les valeurs ptsHome et ptsAway de la table Game sont correctes. -- SELECT g.id AS idGame, t.id AS idTeam, g.ptsHome, g.ptsAway, PtsTotJoueur(g.id, g.idHomeTeam) AS ptsHome1, PtsTotJoueur(g.id, g.idVisitorTeam) AS ptsAway2 -- FROM GAME g, Team t -- WHERE g.idVisitorTeam = t.id; -- -- ? 8 - Quelle table contient des données incorrectes/incomplètes ? Game ou GameDetail ? Vérifier grâce aux résultats officiels des matchs. -- ? 9 - Ecrire une fonction isBestAtHome qui retourne un booléen indiquant si une équipe donnée a -- ? gagné au moins autant de matchs à domicile qu’à l’extérieur lors de la saison passée en paramètre. CREATE OR REPLACE FUNCTION isBestAtHome(IdTeam Team.id%TYPE, GameSeason Game.season%TYPE) RETURNS numeric AS $$ DECLARE home_wins integer; away_wins integer; BEGIN SELECT COUNT(*) INTO home_wins FROM GAME g WHERE g.season = GameSeason AND g.idHomeTeam = IdTeam AND g.ptsHome > g.ptsAway; SELECT COUNT(*) INTO away_wins FROM GAME g WHERE g.season = GameSeason AND g.idVisitorTeam = IdTeam AND g.ptsAway > g.ptsHome; IF (home_wins >= away_wins) THEN RETURN 1; ELSE RETURN 0; END IF; END; $$ LANGUAGE plpgsql; -- ? 10 - Vérifier que l’équipe des Spurs a été meilleure à domicile qu’à l’extérieur pendant la saison 2021. SELECT isBestAtHome(id, '2021') AS best_at_home FROM Team WHERE abbreviation = 'SAS'; -- ? 11 - Ecrire une fonction bestAtHome qui retourne une table avec les équipes (ids, abbréviations, noms et villes) -- ? qui ont gagné au moins autant de matchs à domicile qu’à l’extérieur lors de la saison passée en paramètre. CREATE OR REPLACE FUNCTION BestAtHome(GameSeason Game.season%TYPE) RETURNS TABLE(id Team.id%TYPE, abbreviation Team.abbreviation%TYPE, nom Team.nickname%TYPE, ville Team.city%TYPE) AS $$ BEGIN RETURN QUERY SELECT DISTINCT t.id, t.abbreviation, t.nickname, t.city FROM Team t WHERE isBestAtHome(t.id, GameSeason) = 1; END; $$ LANGUAGE plpgsql; -- ? 12 - Quelles équipes ont gagné au moins autant de matchs à domicile qu’à l’extérieur en 2021? SELECT BestAtHome(2021); -- ? 13 - Ecrire une fonction qui retourne un booléen indiquant si une équipe donnée à gagner au moins autant de matchs à -- ? domiciles qu’à l’extérieur pendant au moins n saisons consécutives, où n est un paramètre de la fonction. -- ? Cette fonction devra lever une exception personnalisée si n n’est pas une valeur possible. CREATE OR REPLACE FUNCTION isBestAtHomeDuring(nbSeason numeric) RETURNS numeric AS $$ DECLARE home_wins integer; away_wins integer; BEGIN SELECT COUNT(*) INTO home_wins FROM GAME g, Team t WHERE g.idHomeTeam = t.id AND isBestAtHome(t.id, g.season) = 1; SELECT COUNT(*) INTO away_wins FROM GAME g, Team t WHERE g.idVisitorTeam = t.id AND isBestAtHome(t.id, g.season) = 0; IF (home_wins >= away_wins) THEN RETURN 1; ELSE RETURN 0; END IF; END; $$ LANGUAGE plpgsql; -- SELECT isBestAtHomeDuring(5); -- ? 14 - Y a t’il des équipes qui ont gagné au moins autant de matchs à domicile qu’à l’extérieur -- ? pendant 2 saisons consécutives ? Pendant 3 saisons consécutives ? -- ? 15 - Écrire une fonction qui calcule l’id de l’équipe ayant le meilleur pourcentage moyen de paniers -- ? à 3 points d’une saison donnée. CREATE OR REPLACE FUNCTION idTeam3Points(GameSeason Game.season%TYPE) RETURNS numeric AS $$ DECLARE idTeam Team.id%TYPE; BEGIN SELECT t.id INTO idTeam FROM Team t, GameDetail gd, Game g WHERE gd.idTeam = t.id AND gd.idGame = g.id AND g.season = GameSeason AND gd.threePointsPrctage >= ALL(SELECT threePointsPrctage FROM GameDetail gd1 WHERE gd1.idTeam = t.id); RETURN idTeam; END; $$ LANGUAGE plpgsql; -- ? 16 - Utiliser cette fonction pour afficher la meilleure équipe (abbréviation, nom et ville) de la saison 2021 en pourcentage moyen de paniers à 3 points SELECT t.id, t.abbreviation, t.nickname, t.city FROM Team t WHERE idTeam3Points('2021') = t.id; -- ? 17 - Écrire une fonction qui calcule combien de paniers à trois points ont été marqué par un joueur donné, pendant une saison donnée. CREATE OR REPLACE FUNCTION idTeam3Points(idPlayer Player.id%TYPE , GameSeason Game.season%TYPE) RETURNS numeric AS $$ DECLARE idTeam Team.id%TYPE; BEGIN SELECT t.id INTO idTeam FROM Team t, GameDetail gd, Game g, Player p WHERE gd.idTeam = t.id AND gd.idGame = g.id AND p.id = idPlayer AND g.season = GameSeason AND gd.threePointsPrctage >= ALL(SELECT threePointsPrctage FROM GameDetail gd1 WHERE gd1.idTeam = t.id); RETURN idTeam; END; $$ LANGUAGE plpgsql; -- ? 18 - Écrire une fonction qui calcule l’id du joueur ayant marqué le plus de paniers à trois points pendant une saison donnée. -- ? 19 - En utilisant les fonctions précédement créées, écrire un bloc anonyme qui affiche pour chaque saison, par ordre chronologique, -- ? le nom du joueur ayant marqué le plus de paniers à trois points ainsi que le nombres de paniers à trois points marqués. -- ? 20 - Ce calcul est très long. Pour effectuer un calcul plus efficace, nous allons créer une table supplémentaire permettant de stocker des statistiques. -- ? Créer la table Stats(season, player, threePoints) contenant le nombre de paniers à trois points marqués par chaque joueur pendant une saison et -- ? la remplir avec les données contenues dans GameDetail. -- ? △! Penser à éliminer les valeurs NULL.