diff --git a/seance3_4h/consignes_BE#3.md b/seance3_4h/consignes_BE#3.md index 860bf89db19e4b6509f2a1c283ff177efdee864e..a1f9c89084a28cd21825304067a040706df46d1a 100644 --- a/seance3_4h/consignes_BE#3.md +++ b/seance3_4h/consignes_BE#3.md @@ -1,30 +1,30 @@ ### Consignes pour le rendu (BE #3 - INF-TC2) -Ce BE est le premier devoir à rendre concernant INF-TC2. Le compte-rendu (CR) de votre travail devra être déposé sur `Pedagogie1`, sur l'espace de dépôt spécifique à votre groupe. Et cela dans un **délai d'une semaine après la dernière séance consacrée à ce BE** (délai de rigueur, aucun travail accepté au delà de cette date). Cette semaine ne tient pas compte d'éventuelles vacances. Si vous avez un doute, le plus simple est de contrôler la date pour votre groupe sur `Pedagogie1`. +Ce BE est le premier devoir à rendre concernant INF-TC2. Le compte-rendu (CR) de votre travail devra être déposé sur _Pedagogie1_, sur l'espace de dépôt spécifique à votre groupe. Et cela dans un **délai d'une semaine après la dernière séance consacrée à ce BE** (délai de rigueur, aucun travail accepté au delà de cette date). Cette semaine de délai ne tient pas compte d'éventuelles vacances. Si vous avez un doute, le plus simple est de contrôler la date pour votre groupe sur _Pedagogie1_. **Consignes:** - - Le travail peut être individuel ou en binôme. Si vous travaillez en binôme, **un seul dépôt suffit !**. - - Le dépôt consistera en une unique archive (zip, rar ou tgz) contenant l'ensemble des fichiers suivants : +> - Le travail peut être individuel ou en binôme. Si vous travaillez en binôme, **un seul dépôt suffit !**. +> - Le dépôt consistera en une unique archive (zip, rar ou tgz) contenant l'ensemble des fichiers suivants : - La base de données *Hotellerie.db*, après exécution des requêtes de l'énoncé. - Le fichier _HotelDB.py_, contenant la classe **HotelDB** et un programme principal permettant de rejouer l'ensemble des requêtes de cet énoncé. - - La base de données de votre choix pour les 2 requêtes libres : si vous choisissez cette option, n'oubliez pas d'inclure la nouvelle bdd dans votre archive (si elle est très volumineuse, donnez uniquement le chemin de téléchargement dans votre rapport), ainsi que le fichier _Python_ qui réalise les requêtes que vous aurez imaginées. + - La base de données de votre choix pour les 2 requêtes libres (si différentes de *Hotellerie.db*) ; Si elle est très volumineuse, donnez uniquement le chemin de téléchargement dans votre rapport). Ajoutez le fichier _Python_ qui met en œuvre les requêtes que vous aurez imaginées. - Un rapport (format _pdf_ exclusivement) contenant - une en-tête où devront figurer le nom des élèves, leur numéro de groupe, le nom de l'encadrant ainsi que le titre du BE. - des commentaires sur la programmation de chacune des requêtes et les résultats obtenus. - tout diagramme, toute figure ou toute explication que vous jugerez utile, mais dans un **nombre de pages limité à 10** (il n'est pas demandé de rédiger 10 pages, c'est une limite à ne pas dépasser !). - - L'archive devra nécessairement porter le nom suivant : *nom1-BE3.zip* ou *nom1-nom2-BE3.zip* (pour les étourdis, pensez à remplacer *nom1* et *nom2* par vos propres noms :-) ) +> - L'archive devra nécessairement porter le nom suivant : *nom1-BE3.zip* ou *nom1-nom2-BE3.zip* (pour les étourdis, pensez à remplacer *nom1* et *nom2* par vos propres noms :-) ) **Critères d'évaluation du travail** Voici une liste (non exhaustive) de critères qui permettront à vos encadrants d'évaluer vos requêtes : -- **Qualité du rapport** : apparence visuelle globale, orthographe, structure du rapport claire et cohérente. Qualité des représentations graphique (légendes, label sur les axes...). +> - **Qualité du rapport** : apparence visuelle globale (lisibilité), orthographe, structure du rapport claire et cohérente. Qualité des représentations graphique (légendes, label sur les axes...). -- **Qualité de l'API** : choix des noms et arguments des méthodes, pas de requêtes SQL hors de la classe, affichages textuel et graphique forcément en dehors des méthodes-requêtes. +> - **Qualité de l'API** : choix des noms et arguments des méthodes, pas de requêtes SQL hors de la classe, code d'affichage des texte et des graphiques forcément en dehors des méthodes-requêtes. -- **Qualité du code** : est-ce qu'il fonctionne sans erreur, le code est-il suffisamment commenté et aéré ? Tests multiples avec des paramètres inattendus ou erronés. Interception des erreurs potentielles par des exceptions. +> - **Qualité du code** : est-ce qu'il fonctionne sans erreur, le code est-il suffisamment commenté et aéré ? Tests multiples avec des paramètres inattendus ou erronés. Interception des erreurs potentielles par des exceptions. -- **Qualité des requêtes** : originalité et justification de l'intérêt, difficulté technique, valorisation dans le rapport. +> - **Qualité des requêtes** : originalité et justification de l'intérêt, difficulté technique, valorisation dans le rapport. \ No newline at end of file diff --git a/seance3_4h/seance3_4h.md b/seance3_4h/seance3_4h.md index 44f49e76b9b3ab2fd5700d900f4f83486bb0eeef..b80d1b7c6a772b4ccc6404fd912482b498e732e2 100644 --- a/seance3_4h/seance3_4h.md +++ b/seance3_4h/seance3_4h.md @@ -4,18 +4,27 @@ # BE #3 : Exceptions et Base de données SQL -L'objectif principal de ce BE concerne l'utilisation **des exceptions** pour améliorer la robustesse d'un code. Pour expérimenter ce concept clé, nous nous servirons du prétexte de la manipulation de bases de données à l'aide de requêtes _SQL_ (*Structured Query Language*), écrites en _Python_. Ce BE est décomposé en trois parties : +__Ceci est la version enseignants incluant les corrections__ + +__Note aux enseignants__ Ce document est la __version enseignant__ du BE #3 incluant les solutions aux questions posées. L'énoncé porte sur l'utilisation des exceptions, dans le contexte de la manipulation de bases SQL en POO. Il reprend la même librairie (_sqlite3_) que le BE #1 de INF-TC3. Ce BE doit également permettre aux étudiants d'utiliser la librairie graphique orientée objet _matplotlib.pyplot_ pour illustrer les requêtes de la dernière partie (cf _Requêtes libres_). + +Ce BE sera noté, les consignes pour rendre le travail sont expliquées dans le fichier _consignes_BE#3.md_, disponible au même endroit que cet énoncé. Pendant les 2 premières heures, les élèves vont apprendre à gérer des exceptions provoquées par des requêtes SQL avec la librairie _sqlite3_ (et se remémorer la syntaxe _SQL_). Les 2 heures suivantes (en autonomie) sont consacrées au design et à l'implémentation de 2 requêtes, à partir d'une bdd de leur choix. Cela doit permettre à chaque étudiant de faire un rendu personnalisé (requêtes et affichages graphiques des résultats), tout en prenant soin de la robustesse de leur code grâce aux exceptions. Cela devrait favoriser un travail personnel des étudiants/binômes puisque chaque requête doit être unique. + +Dans le support de cours, les explications concernant la gestion des exceptions commencent à la planche #55 (cf fichier _Python++.pdf_ sur _Pedagogie1_). + +--- +L'objectif principal de ce BE concerne l'utilisation **des exceptions** ([lien](https://docs.python.org/fr/3/tutorial/errors.html) officiel, [tuto _devstory_](https://devstory.net/11421/python-exception-handling) sur les exceptions) pour améliorer la robustesse d'un code. Pour expérimenter ce concept clé, nous nous servirons du prétexte de la manipulation de bases de données à l'aide de requêtes _SQL_ (_Structured Query Language_), écrites en _Python_. Ce BE est composé de trois parties : 1. **La première partie** (durée: 45 min.) présente quelques commandes élémentaires pour interroger une base _SQL_ à partir de _Python_; 1. **La seconde partie** (durée: 75 min.) permet de découvrir comment manipuler une base de données _SQL_ en _Python_ orienté objet. 1. **La troisième partie** (durée: 120 min. et +) vous engage dans un travail plus personnalisé, pour mettre à profit vos connaissances sur la gestion des exceptions, la librairie graphique *matplotlib* et le langage d'interrogation de bases _SQL_. -Ce BE fera l'objet d'un compte-rendu (CR), seul ou en binôme. Avant de commencer, veuillez prendre connaissance des consignes concernant le rendu du travail (à respecter scrupuleusement) qui se trouvent dans le fichier [consignes_BE#3.md](./consignes_BE#3.md) (dans le même répertoire que cet énoncé). Les critères de notations y sont donnés. +Ce BE fera l'objet d'un compte-rendu (CR), seul ou en binôme. Avant de commencer, veuillez prendre connaissance des consignes concernant le rendu du travail (à respecter scrupuleusement) qui se trouvent dans le fichier [consignes_BE#3.md](./consignes_BE#3.md) (dans le même répertoire que cet énoncé). Les critères de notation y sont présentés. --- ## 1. Mini-tutoriel sur la base Hotellerie.db (45 min.) -Le système de gestion de base de données qui sera utilisé durant ce BE est _SQLite_. Ce système très simple stocke une base de données dans un fichier d'extension _.sqlite_. La base de tests que nous allons utiliser dans cette partie (_hotellerie.db_) est disponible au même endroit que cet énoncé. Son schéma est le suivant : +Le système de gestion de base de données (SGBD) qui sera utilisé durant ce BE est _SQLite_. Ce système stocke une base de données dans un fichier d'extension _.sqlite_. La base de tests que nous allons utiliser dans cette partie (_hotellerie.db_) est disponible au même endroit que cet énoncé. Son schéma est le suivant : <center><img src="figures/schema_bdd_hotellerie.png" style="width:70%"/></center> @@ -27,7 +36,7 @@ La base est composée de 5 tables, ces tables étant composées d'un nombre vari ### 1.1 DB browser for SQLite (15 min.) -Toutes les opérations sur une base de données de ce type peuvent être effectuées en _Python_ via les classes et les méthodes présentes au sein du module _sqlite3_. Pour manipuler de manière interactive le contenu de la base (créer, supprimer ou modifier des tables et des enregistrements, effectuer des requêtes _SQL_...), il existe des outils adaptés. L'outil retenu dans le cadre de ce BE s'appelle ``DB Browser for SQLite``. C'est un logiciel libre qui existe pour toutes les plate-formes : _Windows_, _MacOs_, nombreuses distributions _Linux_ et _Unix_... +Toutes les opérations sur une base de données de ce type peuvent être effectuées en _Python_ via les classes et les méthodes présentes au sein du module _sqlite3_ ([doc officielle de la librairie](https://docs.python.org/3/library/sqlite3.html)). Pour manipuler de manière interactive le contenu de la base (créer, supprimer ou modifier des tables et des enregistrements, effectuer des requêtes _SQL_...), il existe des outils adaptés. L'outil retenu dans le cadre de ce BE s'appelle ``DB Browser for SQLite``. C'est un logiciel libre qui existe pour toutes les plate-formes : _Windows_, _MacOs_, nombreuses distributions _Linux_ et _Unix_... - Téléchargez et installez [DB Browser for SQLite](https://sqlitebrowser.org/) en suivant les instructions d'installation adaptées à votre système d'exploitation. - Avec ce logiciel, ouvrez la base *hotellerie.db* et naviguez dans les tables (onglet `Structure de la Base de Données`) et les enregistrements (onglet `Parcourir les données`) pour prendre connaissance de la base (telle qu'elle est schématisée ci-dessus). @@ -39,18 +48,18 @@ Toutes les opérations sur une base de données de ce type peuvent être effectu SELECT nom, ville FROM hotel; ``` -La réponse apparaît sous forme de 12 lignes. Ça vous rappelle des choses ? Si non, alors voici quelques pointeurs pour vous rafraîchir la mémoire : - - [cours tutoriel sur SQL](https://www.1keydata.com/fr/sql/) - - [SQL : sélection, jointure, regroupement, filtre](http://cerig.pagora.grenoble-inp.fr/tutoriel/bases-de-donnees/chap20.htm) - - et tant d'autres... +La réponse apparaît sous forme de 12 lignes. Ça vous rappelle des choses ? Si non, alors voici quelques pointeurs pour vous rafraîchir la mémoire : + - [cours tutoriel sur SQL](https://www.1keydata.com/fr/sql/) + - [SQL : sélection, jointure, regroupement, filtre](http://cerig.pagora.grenoble-inp.fr/tutoriel/bases-de-donnees/chap20.htm) + - et tant d'autres... ### 1.2 Quelques requêtes en _Python_ (15 min.) -**Attention** Avant de lancer un requête sur la bdd avec _Python_, il est fortement conseillé de fermer `DB Browser for SQLite`, sinon vous pourriez soit avoir un plantage de votre programme, soit détruire la bdd (auquel cas il vous suffirait de la télécharger à nouveau). +**Attention** Avant de lancer un requête sur la bdd avec _Python_, il est fortement conseillé de fermer `DB Browser for SQLite`, sinon vous pourriez soit avoir un plantage de votre programme, soit détruire la bdd (auquel cas il vous suffirait de la télécharger à nouveau depuis ce site Web). -Nous allons à présent chercher à reproduire la requête ci-dessus en utilisant _Python_ et le package _sqlite3_. C'est une librairie objet dont la [documentation](https://docs.python.org/3/library/sqlite3.html#module-sqlite3) fournit une description des classes et des méthodes disponibles. Suivez le guide... +Nous allons à présent chercher à reproduire la requête ci-dessus en utilisant _Python_ et le package _sqlite3_. C'est une librairie objet dont la [documentation](https://docs.python.org/3/library/sqlite3.html#module-sqlite3) fournit une description des classes et des méthodes disponibles. Suivez le guide... Le squelette typique d'un tel programme s'écrit : ```python @@ -73,9 +82,9 @@ if __name__ == '__main__': curseur = conn.cursor() # objet permettant de faire des requêtes curseur.execute("SELECT nom, ville FROM hotel;") # requête SQL - ligne1 = curseur.fetchone() # recupère la 1ère ligne du résultat de la requête + ligne1 = curseur.fetchone() # récupère la 1ère ligne du résultat de la requête print('ligne1 =', ligne1) - ligneAll = curseur.fetchall() # recupère toutes les lignes du résultat de la requête + ligneAll = curseur.fetchall() # récupère toutes les lignes suivantes print('ligneAll =', ligneAll) conn.close() @@ -91,7 +100,7 @@ Copiez et exécutez ce programme ; le résultat se présente sous forme d'un tup print(ligneAll[0][0]) ``` -Voici un usage intéressant à étudier : +Voici un usage intéressant à tester : ```python import sqlite3 if __name__ == '__main__': @@ -106,10 +115,10 @@ if __name__ == '__main__': ### 1.3 La gestion des exceptions (15 min.) -Les quelques lignes de code que nous venons d'étudier peuvent être à l'origine de nombreux problèmes lors de l'exécution : +Les quelques lignes de code précédentes peuvent être à l'origine de nombreux problèmes lors de l'exécution : - la base de données est introuvable; - - le nom des tables ou des champs dans la requête sont erronés; + - les noms des tables et/ou des champs dans la requête sont erronés; - ... Voyons maintenant comment intercepter les exceptions lancées dans ces cas de figure par les méthodes de la librairie `sqlite3`. Pour cela, veuillez d'abord copier et exécuter le programme suivant : @@ -132,13 +141,36 @@ if __name__ == '__main__': A priori, ce programme ne lance pas d'exception. Modifiez-le pour faire apparaître les 2 problèmes énoncés ci-dessus. Pour cela : - Changez le nom de la bdd dans le programme, p. ex. _impossible.db_. Comment interprétez-vous le message d'erreur en observant le contenu de votre répertoire de travail ? - - Revenez au nom correct du fichier : _hotellerie.db_. Testez alors le changement de nom des tables, puis des champs. + - Revenez au nom correct du fichier : _hotellerie.db_. Testez alors des noms erronés pour les tables, puis pour les champs. -On constate que, dans chaque situation, l'exception `OperationalError` est lancée, avec des messages d'information différents qui précisent le type d'erreur. Remplacez alors le code `except Exception as err:` par le code `except sqlite3.OperationalError as err:`, et vérifiez que cela fonctionne de la même manière que précédemment. +On constate, dans chaque situation, que l'exception `sqlite3.OperationalError` est lancée, avec des messages d'information différents qui précisent le type d'erreur. Remplacez alors le code `except Exception as err:` par le code `except sqlite3.OperationalError as err:`, et vérifiez que cela fonctionne de la même manière que précédemment. La liste des exceptions lancées par l'usage de commandes `sqlite3` est disponible en suivant [ce lien](https://docs.python.org/3/library/sqlite3.html#exceptions). Prenez le temps de lire la description des différentes exceptions. Toutes les exceptions de ce module héritent d'une classe appelée __sqlite3.Error__ (elle-même héritant de la classe de base de gestion des exceptions de _Python_ : __Exception__). +--- +<p class=correction> +<b>Éléments de réponse pour les enseignants</b> +</p> + +Si on donne un mauvais nom pour la Bdd, alors elle est ouverte en écriture (et donc vide), d'où l'erreur sur le nom de la table. + +```python +# programme importBdd_3.py +import sqlite3 +if __name__ == '__main__': + try: + conn = sqlite3.connect('hotellerie.db') + curseur = conn.cursor() + curseur.execute("SELECT nom, ville FROM hotel;") + print(curseur.fetchall()) + except sqlite3.OperationalError as err: # interception d'une exception spécifique + print('err:', str(err)) + print('type exception:', type(err).__name__) + finally: # fermeture de la base dans tous les cas + conn.close() +``` + --- ## 2. Classe HotelDB (75 min.) @@ -170,15 +202,79 @@ def __del__ (self): __Améliorations à implémenter__ : - - Comment se comporte votre programme si on insère cet appel `aHotelDB.get_name_hotel_etoile(-1)` dans le programme principal ? Truc: exception standard **ValueError** ou **AssertionError**. - - Comment se comporte votre programme si on insère cet appel `aHotelDB.get_name_hotel_etoile("Hello")` ? Truc: exception standard **TypeError**. + - Comment se comporte votre programme si on insère cet appel `aHotelDB.get_name_hotel_etoile(-1)` dans le programme principal ? **Truc:** exception standard **ValueError** ou **AssertionError**. + - Comment se comporte votre programme si on insère cet appel `aHotelDB.get_name_hotel_etoile("Hello")` ? **Truc:** exception standard **TypeError**. Veillez à ce que ces _appels erronés_ renvoient une liste vide tout simplement. +--- +<p class=correction> +<b>Éléments de réponse pour les enseignants</b> +</p> + +_Remarque_ : insister sur la gestion des exceptions pour traiter des arguments erronés + en type (_P. ex._ chaîne de caractères au lieu d'un entier). + +```python +import sqlite3 + +class HotelDB: + + def __init__(self, nom): + self.__DBname = nom + self.__conn = sqlite3.connect(self.__DBname) + + def get_name_hotel_etoile(self, nbetoiles): + curseur = self.__conn.cursor() + liste = [] + try: + # assert nbetoiles>0, "Le nbre d'étoiles doit être > 0 !" # peut remplacer la suivante + if nbetoiles<=0: + raise ValueError("Le nbre d'étoiles doit être > 0 !") + #curseur.execute('SELECT nom FROM hotel WHERE etoiles=%d' % nbetoiles) # obsolete + #curseur.execute('SELECT nom FROM hotel WHERE etoiles=?', (nbetoiles,)) # secure + curseur.execute('SELECT nom FROM hotel WHERE etoiles={}'.format(nbetoiles)) + except sqlite3.OperationalError as sqlerr: + print('{} in {}'.format(str(sqlerr), self.__DBname)) + except TypeError as typerr: + print('TypeError: {}'.format(str(typerr))) + except ValueError as valerr: + print('ValueError: {}'.format(str(valerr))) + # except AssertionError as asserr: + # print('AssertionError: {}'.format(str(asserr))) + else: + liste = curseur.fetchall() + + return liste + + def __del__ (self): + self.__conn.close() + def __str__(self): + return 'Base de données : ' + self.__DBname + +if __name__ == '__main__': + + aHotelDB = HotelDB('hotellerie.db') + nbEtoiles = 2 + resultat = aHotelDB.get_name_hotel_etoile(nbEtoiles) + print("Liste des noms d'hotel", nbEtoiles, "étoiles : ", resultat) + + print("Liste des noms d'hotel : ", aHotelDB.get_name_hotel_etoile(-1)) + print("Liste des noms d'hotel : ", aHotelDB.get_name_hotel_etoile("Hello")) +``` + +Ce qui donne +``` +Liste des noms d'hotel 2 étoiles : [('La nuit noire',), ('Hotel chez soi',), ('Chez Philippe',)] +ValueError: Le nbre d'étoiles doit être > 0 ! +Liste des noms d'hotel : [] +TypeError: '<=' not supported between instances of 'str' and 'int' +Liste des noms d'hotel : [] +``` ### 2.2 Requête en écriture (45 min.) -Créer une requête permettant d'ajouter un nouveau client et de renvoyer son identifiant (c'est à dire son _numclient_). Si le client existe déjà (même nom ET même prénom), la méthode renverra son _numclient_ (on supposera, pour des raisons de simplification, qu'il n'y a pas clients homonymes). Pour cette requête, renseignez-vous sur la commande `INSERT INTO`. _Attention_ la clé primaire sera renseignée automatiquement, pas besoin de la stipuler. Notez également que l'attribut _curseur.lastrowid_ permet de récupérer le _numclient_ du nouveau client. +Créer une requête permettant d'ajouter un nouveau client et de renvoyer son identifiant (c'est à dire son _numclient_). Si le client existe déjà (même nom ET même prénom), la méthode renverra son _numclient_ (on supposera qu'il n'y a pas clients homonymes). Pour cette requête, renseignez-vous sur la commande `INSERT INTO`. _Attention_ la clé primaire sera renseignée automatiquement, pas besoin de la préciser explicitement. Notez également que l'attribut _curseur.lastrowid_ permet de récupérer le _numclient_ du nouveau client. Vérifier que le nouveau client a bien été sauvegardé dans le fichier *Hotellerie.db* : @@ -187,33 +283,91 @@ Vérifier que le nouveau client a bien été sauvegardé dans le fichier *Hotell _Remarques_ : - - Pensez à quitter le logiciel `DB Browser` avant d'exécuter votre programme. + - Pensez à quitter le logiciel `DB Browser for SQLite` avant d'exécuter votre programme. - En cas de destruction de la base `Hotellerie.db` (les requêtes en écriture sont toujours plus dangereuses que les requêtes en lecture !), pensez à la télécharger à nouveau ! +------ +<p class=correction> +<b>Éléments de réponse pour les enseignants</b> +</p> + +```python +import sqlite3 + +class HotelDB: + + ... + + def add_new_client(self, prenom, nom): + # On recherche si le client est là ! + curseur = self.__conn.cursor() + try: + #curseur.execute("SELECT numclient FROM client WHERE nom='%s' \ + # AND prenom='%s'" % (nom, prenom)) # obsolete + #curseur.execute("SELECT numclient FROM client WHERE nom=? \ + # AND prenom=?", (nom, prenom)) # secure + curseur.execute("SELECT numclient FROM client WHERE nom='{}' \ + AND prenom='{}'".format(nom, prenom)) + except sqlite3.OperationalError as sqlerr: + print('{} in {}'.format(str(sqlerr), self.__DBname)) + return None + + liste = curseur.fetchall() # pas d'homonyme dans le fichier + if len(liste) != 0: + print('Le client existe déjà') + return liste[0] + + # on ajoute le client (la clé primaire est ajouté automatiquement) + curseur.execute("INSERT INTO client(nom, prenom) VALUES ('{}', '{}')".format(nom, prenom)) + + # Ne pas oublier de MAJ le fichier + self.__conn.commit() + return curseur.lastrowid + + +if __name__ == '__main__': + + aHotelDB = HotelDB('hotellerie.db') + # IDClient1 = aHotelDB.add_new_client("Svetlana", "Kapriski") + # print('ID client:', IDClient1) + IDClient2 = aHotelDB.add_new_client("Toto", "Zero") # + print('ID client:', IDClient2) + +``` + +Ce qui donne, lors de la première exécution +```bash +ID client: 180 +``` +et lors de la seconde exécution +```bash +Le client existe déjà +ID client: 180 +``` --- ## 3. Requêtes libres (120 min. et +) Dans cette dernière partie, nous vous invitons à imaginer et implémenter **DEUX (2)** requêtes originales à partir de la bdd *Hotellerie.db*, ou de tout autre bdd que vous aurez trouvée sur Internet. -Les résultats de vos requêtes devront faire l'objet d'une représentation graphique (graphe, histogramme, camembert...) en utilisant la librairie _Matplotlib_ (cf les remarques ci-dessous). +Les résultats de vos requêtes devront faire l'objet d'une représentation graphique (graphe, histogramme, camembert...) en utilisant la librairie _Matplotlib_ (cf remarques ci-dessous). Vous pouvez _justifier_ la robustesse de vos requêtes en écrivant, dans votre programme principal, plusieurs appels à vos requêtes avec des paramètres farfelus, erronés... Bonus à ceux qui développerons une exception propre ! -### Liens vers des Bdds `sqlite` +### Liens vers quelques Bdds `sqlite` Voici quelques exemples de sites proposant des bdd _SQLite_ gratuites : - - Une base de données de films est étéchargeable en suivant [ce lien](https://1drv.ms/u/s!Ap1xZ3X70U50gvdIaHBrQ5uvSD-WSg?e=ncEblG). Elle est composée de 4 tables (acteur, réalisateur, film, distribution). - - Le site [SQLite tutorial](https://www.sqlitetutorial.net/sqlite-sample-database/) propose un base de données appelée _chinook_ (_digital media store_), composée de 11 tables. - - Dans le même genre, une base de données très célèbre : [Northwind](https://cs.ulb.ac.be/public/_media/teaching/infoh303/northwind_sqlite.db.zip) (8 tables). - - Si vous êtes fan des _Pokémon_, vous pouvez décompresser la base [veekun's Pokédex](http://veekun.com/static/pokedex/downloads/veekun-pokedex.sqlite.gz) (172 tables !). - - Si vous êtes fan de musique, vous pouvez décompresser et utiliser la base [musicBrainz](https://matthieu-moy.fr/cours/infocpp-S3/TPL/musicBrainz.zip) (4 tables). - - Une petite base concernant la [peinture](https://carnot.cpge.info/wp-content/uploads/2020/02/peinture.db). - - Beaucoup plus complexe : [murder-mystery](https://forge.univ-lyon1.fr/diu-eil/bloc4/-/raw/master/3_bases_de_donnees_introduction/TP/base-sql-murder-mystery.db) (9 tables). Lire le [site original](https://github.com/NUKnightLab/sql-mysteries). - - [postuler à Stanford](https://forge.univ-lyon1.fr/diu-eil/bloc4/-/raw/master/3_bases_de_donnees_introduction/TP/base-stanford.db) (3 tables). +> - Une base de données de films est téléchargeable en suivant [ce lien](https://1drv.ms/u/s!Ap1xZ3X70U50gvdIaHBrQ5uvSD-WSg?e=ncEblG). Elle est composée de 4 tables (acteur, réalisateur, film, distribution) +> - Le site [SQLite tutorial](https://www.sqlitetutorial.net/sqlite-sample-database/) propose un base de données appelée _chinook_ (_digital media store_), composée de 11 tables +> - Dans le même genre, une base de données très célèbre : [Northwind](https://cs.ulb.ac.be/public/_media/teaching/infoh303/northwind_sqlite.db.zip) (8 tables) +> - Si vous êtes fan des _Pokémon_, vous pouvez décompresser la base [veekun's Pokédex](http://veekun.com/static/pokedex/downloads/veekun-pokedex.sqlite.gz) (172 tables !) +> - Si vous êtes fan de musique, vous pouvez décompresser et utiliser la base [musicBrainz](https://matthieu-moy.fr/cours/infocpp-S3/TPL/musicBrainz.zip) (4 tables) +> - Une petite base concernant la [peinture](https://carnot.cpge.info/wp-content/uploads/2020/02/peinture.db) +> - Beaucoup plus complexe : [murder-mystery](https://forge.univ-lyon1.fr/diu-eil/bloc4/-/raw/master/3_bases_de_donnees_introduction/TP/base-sql-murder-mystery.db) (9 tables). Lire le [site original](https://github.com/NUKnightLab/sql-mysteries) +> - [Postuler à Stanford](https://forge.univ-lyon1.fr/diu-eil/bloc4/-/raw/master/3_bases_de_donnees_introduction/TP/base-stanford.db) (3 tables). -Vous pouvez également transformer des données du format `.csv` (_Comma Separated Value_) vers le format `.sqlite3`, en suivant ce [tutoriel video](https://tube.ac-lyon.fr/videos/watch/85399ea5-bba0-428b-9470-2d3bb41b7de1). Toutes les données de [data.gouv.fr](https://www.data.gouv.fr/fr/), par exemple, deviennent alors exploitables pour votre CR... +Vous pouvez également transformer des données du format `.csv` (_Comma Separated Value_) vers le format `.sqlite3`, en suivant ce [tutoriel vidéo](https://tube.ac-lyon.fr/videos/watch/85399ea5-bba0-428b-9470-2d3bb41b7de1). Toutes les données _open data_ de [data.gouv.fr](https://www.data.gouv.fr/fr/), par exemple, deviennent alors exploitables pour votre CR... Au cas où vous opteriez pour une bdd originale, n'oubliez pas d'inclure cette base dans votre archive (si elle n'est pas trop volumineuse), et de préciser dans votre rapport le chemin pour la télécharger. @@ -221,12 +375,14 @@ Au cas où vous opteriez pour une bdd originale, n'oubliez pas d'inclure cette b Les deux requêtes attendues doivent être relativement sophistiquées (pas de simples `select XX from YY`). - - Si vous optez pour la bdd `Hotellerie.db`, n'hésitez pas à visiter un site de réservation d'hôtels pour trouver des idées de requêtes intéressantes. _Attention_ : le nom d'un hôtel n'est pas une clé primaire ! Plusieurs hôtels portent le même nom. Par contre, il n'existe pas 2 hôtels de même nom dans la même ville. Pensez-y ! - - Si vous optez pour une autre base, développez une seconde classe dans un second fichier indépendant (sur le modèle de la classe **HotelDB**). +> - Si vous optez pour la bdd `Hotellerie.db`, n'hésitez pas à visiter un site de réservation d'hôtels pour trouver des idées de requêtes intéressantes. _Attention_ : le nom d'un hôtel n'est pas une clé primaire ! Plusieurs hôtels portent le même nom. Par contre, il n'existe pas 2 hôtels de même nom dans la même ville. Pensez-y ! +> - Si vous optez pour une autre base, développez une seconde classe dans un second fichier indépendant (sur le modèle de la classe **HotelDB**). **Remarques** : -- Vous programmerez les représentations graphiques dans le programme principal (et non pas dans la méthode qui traite la requête). En effet, quand on fait une requête sur une base de données, l'affichage graphique ne doit pas être obligatoire. C'est pour cela qu'on sépare la requête de l'affichage de son résultat (qu'il soit au format texte ou au format graphique). +> - Vous programmerez les représentations graphiques dans le programme principal (et non pas dans la méthode qui traite la requête). En effet, quand on fait une requête sur une base de données, l'affichage graphique ne doit pas être obligatoire. C'est pour cela qu'on sépare la requête de l'affichage de son résultat (qu'il soit au format texte ou au format graphique). + +> - Usage de _Matplotlib_ : À titre d'exemples, vous trouverez, à côté de cet énoncé, un fichier nommé [ex_matplotlib.py](./ex_matplotlib.py). L'exécution de ce script génère 4 figures dans le sous-répertoire *figures*. Inspirez-vous largement de ce programme pour vos propres figures. -- Usage de _Matplotlib_ : À titre d'exemples, vous trouverez, à côté de cet énoncé, un fichier nommé [ex_matplotlib.py](./ex_matplotlib.py). L'exécution de ce script génère 4 figures dans le sous-répertoire *figures*. Inspirez-vous largement de ce programme pour vos propres figures. *Conseil*: Évitez de vous lancer dans des requêtes avec des données géographiques, genre `trouver tous les hôtels à moins de 5 kilomètres` car l'usage de cartes géographiques dépasse les attentes de ce qui est demandé ici. +> - *Conseil*: Évitez de vous lancer dans des requêtes avec des données géographiques, genre `trouver tous les hôtels à moins de 5 kilomètres` car l'usage de cartes géographiques dépasse les attentes de ce qui est demandé ici.