\! 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.