Gaudino, casier 5 version 2.0 Lycée Masséna Bases de données - Exercices P.C.S.I.834 I. Exercices I.1. Base d élèves On veut fabriquer une base de données des élèves de première année de prépa d un lycée (on omet la deuxième année. Il y a 4 classes en tout : MPSI, PCSI, BCPST, ECS. La base doit présenter les noms et prénoms, classe, année d entrée (le lycée a ouvert ses portes en 1980, et nous sommes en 2015, lycée d origine (de terminale, et la moyenne générale de chaque élève. En plus, on veut que soit précisé la rue et la ville du lycée d origine (sachant que certaines villes abritent plusieurs lycées, ainsi que le pays de ce lycée (certains pays abritent plusieurs villes.... Quelle structure de base peut répondre à ce problème (on donnera deux bases : une avec une seule table plate, l autre avec plusieurs tables? Écrire alors les requêtes SQL permettant de répondre aux questions suivantes : 1. Tous les renseignements sur les élèves de PCSI. 2. Tous les noms des élèves de PCSI. 3. Tous les noms et prénoms d élèves de PCSI, rentrés après 2000. 4. Le nombre d élèves de BCPST qui viennent d une ville précise (par exemple Nice. Il peut y avoir plusieurs lycée dans cette ville. 5. La moyenne de classe des MPSI de 1999. 6. Les moyennes de classes (toutes années confondues, rangées classe par classe. 7. Les classes dont la moyenne de classes de 1999 est supérieure à 10. Reprendre l exercice avec les requêtes de l algèbre relationnelle. I.2. Un mini-chat On veut programmer un forum (genre Twitter, où des participants viendront déposer des messages. 1. Les participants doivent fournir des renseignements : nom, surnom, âge. 2. Les messages (de simples textes un peu longs doivent être signés (du nom du participant, datés (on n a pas appris à utiliser efficacement les dates : on utilisera donc le format anglosaxon aammjj comme un INTEGER, par exemple 140201 pour le premier février 2014, qui devrait faciliter le classement chronologique, et regroupés par thèmes (les thèmes peuvent être prédéfinis. Questions : 1. Un débutant propose la base suivante : deux tables, une avec les thèmes, l autre avec les participants. Les messages seront stockés dans la table participants, avec un nouveau champ pour chaque nouveau message (champs message1, message2,.... Expliquez la vie à ce plaisantin. 2. Quelle structure de base prendre alors? 3. Avec la structure précédente, quelle commande utiliser pour afficher : (a le nom de tous les participants, ordre alphabétique ; (b le nom des participants majeurs ; (c tous les messages sur un thème donné (le 5 par exemple, par ordre antichronologique ; (d le nombre de message d un participant donné (le 5 par exemple ; (e les deux premiers messages d un participant donné (le 5 par exemple, ordre chronologique ; (f la liste des messages et le pseudo de leur auteur. (g les messages d un participant donné (connu par son nom, toto par exemple ; (h le tableau des participants, avec le nombre de messages ; (i le tableau des meilleurs participants (identifiés par leur id, avec le nombre de messages, pourvu qu il en ait au moins deux (triés par ordre décroissant de nombre de message ; (j le tableau des meilleurs participants (identifiés par leur noms, avec le nombre de messages, pourvu qu il en ait au moins deux (triés par ordre décroissant de nombre de message ; (k les messages (classés par thème, avec affichage du pseudo de l auteur et du thème. 1
I.3. Un loueur de voitures Un loueur de voiture veut une base qui permettra de voir : 1. son fichier client : nom, prénom, actuellement avec un véhicule ou pas - en précisant lequel ; 2. son fichier de véhicules : marque (Peugeot, Renault, Citroën, modèle (208, Clio, C6, Mégane, carburant (Essence, Diesel, Electrique, prix à la journée, véhicule loué ou pas, et à qui ; 3. son fichier de location : tel véhicule a été loué à telle date, et est revenu à telle date, il a été loué à M.Untel ; Quelle structure de base prévoir? On essaiera de ne pas répéter les informations. On peut partir avec l idée que l ordinateur sur lequel on travaille connait la date actuelle, et qu on peut la comparer avec une date entrée dans la base (ce qui est tout-à-fait raisonnable et simple, même si on ne sait pas faire en pratique. I.4. TP 1. Avec SQLite Manager : on va fabriquer la base (réduite du loueur de voiture à la main (c est assez long et pénible. (a Créer une nouvelle base loueur. (b Créer une table (plates voiture1 : fabriquer ces champs : i. un champ id : INTEGER, clé primaire, autoincrement ; ii. un champ marque : TEXT iii. un champ modele : TEXT iv. un champ energie : TEXT v. nombre de places : INTEGER vi. un champ debut : INTEGER vii. un champ fin : INTEGER (c Remplir (à la main, c est un peu long la table avec les données ci-dessous (la date est donnée suivant la convention déjà vue - id n est pas donnée. Peugeot 206 Essence 5 20140101 20140201 Renault Twingo Diesel 4 NULL NULL Citroen C4 Essence 5 20140115 NULL Peugeot 807 Diesel 7 20140101 20140103 Renault Twizzy Electrique 2 20140201 NULL Citroen Berlingo Diesel 5 20140116 20140301 (d Avec l onglet SQL, effectuer quelques requêtes : toutes les voitures, classées par constructeur ; toutes les voitures diesel ; le nombre minimal de place ; toutes les voitures en cours de location. La nullité d un champ se teste avec champ IS NULL ou champ IS NOT NULL, et pas avec le =. (e Créer plusieurs tables qui reprennent ces informations mieux structurées, par exemple une table pour les véhicules (avec le nombre de places, une pour l énergie, et une pour les locations. Les remplir (à la main. (f Reprendre les questions. 2. Avec SQLite Manager : reprendre l exercice sur le mini-chat. La base minichat.sqlite est fournie avec 7 thèmes (math, physique, chimie..., 7 auteurs, et quelques messages (de simples répétitions de lettres sans intérêt. 3. Avec SQLite Manager et Python : on considère la base eleves.sqlite des élèves d une classe prépa décrite plus haut (fournie - les champs rue et pays sont omis. (a Ouvrir la base dans SQLite Manager pour se familiariser avec. (b Écrire une requête SQL qui récupère tous les lycées de la base (par leur id ou leur nom, au choix. (c Mettre cette liste dans une variable Python, nommée listelycee. (d Écrire une requête SQL qui affiche tous les élèves (avec leur classe d une année (2010 par exemple et d un lycée donné. On affichera l ordre alphabétique des noms. (e En Python, écrire la ou les chaines qui permettront de fabriquer un fichier CSV qui regroupe ces données. On rappelle qu il s agit de séparer les renseignements par des virgules (ne pas oublier le passage à la ligne. 2
(f En Python, fabriquer ce fichier CSV! Le tableau commencera par une ligne qui indique la légende (nom, prenom, classe. (g Modifier ce qui précède pour avoir, sur le même fichier, tous les élèves d une même année (2010, regroupés par lycée d origine. Les différents lycées seront séparés par une ligne, et annoncés par leur nom. Avec un peu plus d efforts, on obtiendrait non pas un seul fichier mais un fichier par lycée, sous une présentation un peu plus complète qu un simple CSV, et on enverrait automatiquement ce fichier au lycée concerné. 3
II. Exercices - Correction II.1. Base d élèves On veut fabriquer une base de données des élèves de première année de prépa d un lycée (on omet la deuxième année. Il y a 4 classes en tout : MPSI, PCSI, BCPST, ECS. La base doit présenter les noms et prénoms, classe, année d entrée (le lycée a ouvert ses portes en 1980, et nous sommes en 2015, lycée d origine (de terminale, et la moyenne générale de chaque élève. En plus, on veut que soit précisé la rue et la ville du lycée d origine (sachant que certaines villes abritent plusieurs lycées, ainsi que le pays de ce lycée (certains pays abritent plusieurs villes.... Quelle structure de base peut répondre à ce problème (on donnera deux bases : une avec une seule table plate, l autre avec plusieurs tables? Écrire alors les requêtes SQL permettant de répondre aux questions suivantes : 1. Tous les renseignements sur les élèves de PCSI. 2. Tous les noms des élèves de PCSI. 3. Tous les noms et prénoms d élèves de PCSI, rentrés après 2000. 4. Le nombre d élèves de BCPST qui viennent d une ville précise (par exemple Nice. Il peut y avoir plusieurs lycée dans cette ville. 5. La moyenne de classe des MPSI de 1999. 6. Les moyennes de classes (toutes années confondues, rangées classe par classe. 7. Les classes dont la moyenne de classes de 1999 est supérieure à 10. Reprendre l exercice avec les requêtes de l algèbre relationnelle. 1. Avec une seule table plate en SQL : une table qui admet comme colonnes (on peut rajouter une colonne id si on veut : nom(text, prenom(text, classe(text, année(int, lycee(text, ruelycee(text, villelycee(text, note(real. L inconvénient sera que : il y a un fort risque de faute de frappe (BSPCT, MPCSI,20115,... ; l adresse de chaque lycée est répétée aussi souvent qu il y a un élève qui en est issu (idem pour l année,... il y a un fort risque d incohérence dans le nome ou l adresse d un lycée (Masséna, MASSENA, Massena, 2 AV Félix Faure, 2 avenue F.Faure,..., en l état, il n y a pas de clé primaire évidente. (a Tous les renseignements sur les élèves de PCSI. SELECT * FROM table WHERE classe='pcsi' (b Tous les noms des élèves de PCSI. SELECT nom FROM table WHERE classe='pcsi' (c Tous les noms et prénoms d'élèves de PCSI, rentrés après 2000. SELECT nom,prenom FROM table WHERE (classe='pcsi'and annee>=2000 (d Le nombre d'élèves de BCPST qui viennent d'une ville précise (par exemple Nice. Il peut y avoir plusieurs lycée dans cette ville. SELECT COUNT(* FROM table WHERE villelycee='nice' (e La moyenne de classe des MPSI de 1999. SELECT AVG(moyenne FROM table WHERE (classe='mpsi'and annee=1999 (f Les moyennes de classes (toutes années confondues, rangées classe par classe. SELECT classe,avg(note FROM table GROUP BY classe (g Les classes dont la moyenne de classes de 1999 est supérieure à 10. SELECT classe FROM table WHERE (annee=1999 GROUP BY classe HAVING AVG(note>=10 2. Avec une seule table plate en algèbre relationnelle : on prend la même relation (nommée table. (a Tous les renseignements sur les élèves de PCSI. σ classe= P CSI (table (b Tous les noms des élèves de PCSI. π nom σ classe= P CSI (table (c Tous les noms et prénoms d élèves de PCSI, rentrés après 2000. π nom,prenom σ classe= P CSI σ annee>=2000(table (d Le nombre d élèves de BCPST qui viennent d une ville précise (par exemple Nice. Il peut y avoir plusieurs lycée dans cette ville. γ comptage(nom σ villelycee= NICE (table. En fait, il y a un problème sur l attribut compté, car ce n est peut-être pas une clé primaire (il faudrait probablement ajouter une colonne id pour être tranquille. (e La moyenne de classe des MPSI de 1999. γ moyenne(note σ classe= MP SI σ annee=1999(table. (f Les moyennes de classes (toutes années confondues, rangées classe par classe. classe γ moyenne(note (table mais la classe s affichera aussi. Il faut donc plutôt π moyenne(note classe γ moyenne(moyenne (table 4
(g Les classes dont la moyenne de classes de 1999 est supérieure à 10. π classe σ moyenne(note>=10 classe γ moyenne(note σ annee=1999 (table 3. Avec plusieurs tables : On fait (toutes les tables ont un index non rappelé dans la suite : une table eleves, qui aura comme clés étrangères des pointeurs vers toutes les autres tables (sauf ville. Les champs sont nom, prenom, note, classe, annee, lycee (les trois derniers sont des pointeurs ; une table annee, sans clé étrangère. Un seul champ, l année ; une table classe, sans clé étrangère. Un seul champ, la classe ; une table lycee, qui aura comme clé étrangère un pointeur vers la table ville. Trois champs : le lycée, la rue, et un pointeur vers la ville ; une table ville, sans clé étrangère. Les champs sont nom, pays. On pourrait faire aussi une autre table avec les pays. On construit donc les tables ville, classe, annee (dans l ordre qu on veut. Puis la table lyceeterminale. Et enfin la table eleves. De manière générale, ce n est pas très malin : par exemple classe renvoie à trois choses distinctes, une table et deux champs de tables distinctes. Attention à ne pas se mélanger. Le mieux est quand même de choisir des noms moins trompeurs. (a Tous les renseignements sur les élèves de PCSI. C est très pénible (il faut joindre toutes les tables et c est normal : cette requête n est pas réaliste (pensez à la requête qui présente toutes les données de Facebook, par exemple. (b Tous les noms des élèves de PCSI. SELECT nom FROM eleves JOIN classe ON eleves.classe=classe.id WHERE classe.classe='pcsi' π nom σ classe.classe= P CSI (eleves classe eleves.classe=classe.id (c Tous les noms et prénoms d élèves de PCSI, rentrés après 2000. SELECT nom,prenom FROM eleves JOIN classe ON eleves.classe=classe.id JOIN annee ON eleve.annee=annee.id WHERE (classe.classe='pcsi'and annee.annee>=2000 π nom,prenom σ classe.classe= P CSI σ annee.annee>=2000 ( eleves classe eleves.classe=classe.id classe eleves.annee=annee.id (d Le nombre d élèves de BCPST qui viennent d'une ville précise (par exemple Nice. Il peut y avoir plusieurs lycée dans cette ville. SELECT COUNT(* FROM eleve JOIN lycee ON lycee.id=eleve.lycee JOIN ville ON ville.id=lycee.ville WHERE ville.nom='nice' γ comptage(nom σ ville.nom=nice (eleve lycee.id=eleve.lycee lycee (e La moyenne de classe des MPSI de 1999. ville ville.id=lycee.ville (f Les moyennes de classes (toutes années confondues, rangées classe par classe. (g Les classes dont la moyenne de classes de 1999 est supérieure à 10. II.2. Un mini-chat On veut programmer un forum (genre Twitter, où des participants viendront déposer des messages. 1. Les participants doivent fournir des renseignements : nom, surnom, âge. 2. Les messages (de simples textes un peu longs doivent être signés (du nom du participant, datés (on n a pas appris à utiliser efficacement les dates : on utilisera donc le format anglosaxon aammjj comme un INTEGER, par exemple 140201 pour le premier février 2014, qui devrait faciliter le classement chronologique, et regroupés par thèmes (les thèmes peuvent être prédéfinis. Questions : 1. Un débutant propose la base suivante : deux tables, une avec les thèmes, l autre avec les participants. Les messages seront stockés dans la table participants, avec un nouveau champ pour chaque nouveau message (champs message1, message2,.... Expliquez la vie à ce plaisantin. La table participants n a pas un nombre fixe de colonnes : comment les nommer, puis les interroger facilement? En créant une table avec un grand nombre préfixé de colonnes. Mais alors, on limite le nombre de messages, et on utilise une table gigantesque même pour les participants très occasionnels. 5
2. Quelle structure de base prendre alors? On fait dans cet ordre (toutes les tables auront une première colonne id, INTEGER, déclarée comme clé principale, autoincrémentée : une table participants, sans clé étrangère. Champs : nom (TEXT, surnom (TEXT, age (INTEGER une table themes, sans clé étrangère. Champ : theme (TEXT et enfin une table messages, qui aura comme clés étrangères un pointeur vers chacune des deux autres. Champs : message (TEXT, auteur, date et theme (INTEGER tous les trois. À chaque nouveau message, cette table sera augmentée d un ligne. 3. Avec la structure précédente, quelle commande utiliser pour afficher (commande SQL et relationnelle : (a le nom de tous les participants, ordre alphabétique ; SELECT nom FROM participants ORDER BY nom ASC π nom (participants et on n a pas appris à coder le ORDER (b le nom des participants majeurs ; SELECT nom FROM participants WHERE age >= 18 π nom σ age>=18 (participants (c tous les messages sur un thème donné (le 5 par exemple, par ordre antichronologique ; SELECT message FROM messages WHERE theme = 5 ORDER BY date DESC π message σ theme=5 (messages et même remarque sur l ordre. (d le nombre de message d un participant donné (le 5 par exemple ; SELECT COUNT(message FROM messages WHERE auteur = 5 γ comptage(message σ auteur=5 (messages (e les deux premiers messages d un participant donné (le 5 par exemple, ordre chronologique ; SELECT message, date FROM messages WHERE auteur = 5 ORDER BY date ASC LIMIT 0,2 et on ne sait faire ni l ordre, ni la limitation en relationnel. (f la liste des messages et le pseudo de leur auteur. SELECT m.message, p.nom FROM messages AS m JOIN participants AS p ON m.auteur = p.id π messages.message,participants.nom (messages auteur=id participants (g les messages d un participant donné (connu par son nom, toto par exemple ; SELECT * FROM messages WHERE auteur = 'toto' ne marche pas, car le nom de l auteur n apparait pas dans message, mais dans participants. Il faut faire une jointure. SELECT m.message FROM messages AS m JOIN participants AS p ON ( p.id = m.auteur WHERE p.nom='etienne' π messages.message σ participants.nom= etienne (messages participants auteur=id (h le tableau des participants, avec le nombre de messages ; SELECT p.nom, COUNT(m.message FROM participants AS p JOIN messages AS m ON m.auteur = p.id GROUP BY p.nom participants.nomγ comptage(messages.message (messages auteur=id participants (i le tableau des meilleurs participants (identifiés par leur id, avec le nombre de messages, pourvu qu il en ait au moins deux (triés par ordre décroissant de nombre de message ; SELECT m.auteur, COUNT(m.message AS c FROM messages AS m GROUP BY m.auteur HAVING c >=2 ORDER BY c DESC σ comptage(messages.message>=2 messages.auteur γ comptage(messages.message (messages (j le tableau des meilleurs participants (identifiés par leur noms, avec le nombre de messages, pourvu qu il en ait au moins deux (triés par ordre décroissant de nombre de message ; SELECT p.nom, COUNT(m.message AS c FROM participants AS p JOIN messages AS m ON m.auteur = p.id GROUP BY p.nom HAVING c >= 2 ORDER BY c DESC σ comptage(messages.message>=2 participants.nom γ comptage(messages.message (messages participants auteur=id (k les messages (classés par thème, avec affichage du pseudo de l auteur et du thème. Il faut deux jointures! SELECT m.message, p.surnom,t.theme, m.date FROM messages AS m JOIN participants as p ON m.auteur=p.id 6
JOIN themes as t ON m.theme = t.id ORDER BY m.theme ASC π messages.message,participants.surnom,themes.theme,messages.date (messages auteur=id participants themes theme=id II.3. Un loueur de voitures Un loueur de voiture veut une base qui permettra de voir : 1. son fichier client : nom, prénom, actuellement avec un véhicule ou pas - en précisant lequel ; 2. son fichier de véhicules : marque (Peugeot,Renault, Citroën, modèle (208, Clio, C6, Mégane, carburant (Essence, Diesel, Electrique, prix à la journée, véhicule loué ou pas, et à qui ; 3. son fichier de location : tel véhicule a été loué à telle date, et est revenu à telle date, il a été loué à M.Untel ; Quelle structure de base prévoir? On essaiera de ne pas répéter les informations. On peut partir avec l idée que l ordinateur sur lequel on travaille connait la date actuelle, et qu on peut la comparer avec une date entrée dans la base (ce qui est tout-à-fait raisonnable et simple, même si on ne sait pas faire en pratique. La difficulté est de ne pas répéter l information. On peut le faire avec : 1. une table client, sans clé étrangère, avec les seuls champs nom et prenom (plus un index ; 2. une table vehicule, sans clé étrangère, avec les seuls champs marque, modèle, carburant, prix à la journée (plus un index ; 3. ou encore une table vehicule avec des clés étrangères, et des champs marque, modèle, carburant (plusieurs possibilités... 4. et enfin une table emprunt avec beaucoup de clés étrangères : avec un index qui sera le numéro de l emprunt, un champ qui qui pointera sur la base client, un champ quoi qui pointera sur la base vehicule, et deux champs debut et fin qui donneront les dates. II.4. TP 1. Avec SQLite Manager : on va fabriquer la base (réduite du loueur de voiture à la main (c est assez long et pénible. (a Créer une nouvelle base loueur. (b Créer une table (plates voiture1 : fabriquer ces champs : i. un champ id : INTEGER, clé primaire, autoincrement ; ii. un champ marque : TEXT iii. un champ modele : TEXT iv. un champ energie : TEXT v. nombre de places : INTEGER vi. un champ debut : INTEGER vii. un champ fin : INTEGER (c Remplir (à la main, c est un peu long la table avec les données ci-dessous (la date est donnée suivant la convention déjà vue - id n est pas donnée. Peugeot 206 Essence 5 20140101 20140201 Renault Twingo Diesel 4 NULL NULL Citroen C4 Essence 5 20140115 NULL Peugeot 807 Diesel 7 20140101 20140103 Renault Twizzy Electrique 2 20140201 NULL Citroen Berlingo Diesel 5 20140116 20140301 (d Avec l onglet SQL, effectuer quelques requêtes : toutes les voitures, classées par constructeur ; SELECT marque, modele FROM voiture1 ORDER BY marque ASC toutes les voitures diesel ; SELECT marque, modele FROM voiture1 WHERE energie = 'Diesel' le nombre minimal de place ; SELECT MIN(places FROM voiture1 toutes les voitures en cours de location. La nullité d un champ se teste avec champ IS NULL ou champ IS NOT NULL, et pas avec le =. SELECT marque, modele FROM voiture1 WHERE debut IS NOT NULL AND fin IS NULL 7
(e Créer plusieurs tables qui reprennent ces informations mieux structurées, par exemple une table pour les véhicules (avec le nombre de places, une pour l énergie, et une pour les locations. Les remplir (à la main. (f Reprendre les questions. Le nombre minimal de place ne change pas. Pour les voitures en cours de location : une jointure SELECT v.marque, v.modele FROM voiture AS v JOIN location AS l ON v.id = l.vehicule WHERE (l.debut IS NOT NULL AND l.fin IS NULL Pour les véhicules diesel : une jointure SELECT v.marque, v.modele FROM voiture AS v JOIN energie AS e ON v.energie = e.id WHERE e.energie = 'Diesel' 2. Avec SQLite Manager : reprendre l exercice sur le mini-chat. La base minichat.sqlite est fournie avec 7 thèmes (math, physique, chimie..., 7 auteurs, et quelques messages (de simples répétitions de lettres sans intérêt. 3. Avec SQLite Manager et Python : on considère la base eleves.sqlite des élèves d une classe prépa décrite plus haut (fournie - les champs rue et pays sont omis. (a Ouvrir la base dans SQLite Manager pour se familiariser avec. (b Écrire une requête SQL qui récupère tous les lycées de la base (par leur id ou leur nom, au choix. SELECT nom FROM lycee ou SELECT id FROM lycee (c Mettre cette liste dans une variable Python, nommée listelycee. connexion =sqlite3.connect("eleves.sqlite" curseur =connexion.cursor( curseur.execute("select nom FROM lycee" listelycee = curseur.fetchall( connexion.commit( #sauve les modifications - inutile si on ne fait que des SELECT connexion.close( (d Écrire une requête SQL qui affiche tous les élèves (avec leur classe d une année (2010 par exemple et d un lycée donné. On affichera l ordre alphabétique des noms. SELECT e.nom, e.prenom FROM eleves AS e WHERE annee = 1 AND lycee = 1 si on connait l id de l année et du lycée. Sinon, il faut faire deux jointures : SELECT e.nom, e.prenom FROM eleves AS e JOIN annee AS a ON e.annee = a.id JOIN lycee AS l ON e.lycee = l.id WHERE (a.annee=2010 AND l.nom='massena' Pour la classe, il faut rajouter : SELECT e.nom, e.prenom, c.classe FROM eleves AS e JOIN annee AS a ON e.annee = a.id JOIN lycee AS l ON e.lycee = l.id JOIN classe AS c ON c.id = e.classe WHERE (a.annee=2010 AND l.nom='massena' ORDER BY e.nom ASC (e En Python, écrire la ou les chaines qui permettront de fabriquer un fichier CSV qui regroupe ces données. On rappelle qu il s agit de séparer les renseignements par des virgules (ne pas oublier le passage à la ligne. On récupère la liste des lignes, chaque ligne étant un tuple, comme décrit plus haut. Notez que ce tuple n est pas une chaine, c est un tuple de chaines. La virgule ne joue pas le bon rôle. for ligne in resultat: chaine = '' for champ in ligne: chaine = chaine + champ + ',' #il y aura une virgule en trop à la fin chaine = chaine + '\n' #A ce stade, chaine contient une ligne, finie par un retour à la ligne (f En Python, fabriquer ce fichier CSV! Le tableau commencera par une ligne qui indique la légende (nom, prenom, classe. Il faut ouvrir un nouveau fichier, y ajouter la légende et ces lignes, puis le fermer. objet = open('donnees.csv', 'w' objet.write('nom,prenom,classe\n' 8
for ligne in resultat: chaine = '' for champ in ligne: chaine = chaine + champ + ',' #il y aura une virgule en trop à la fin chaine = chaine + '\n' objet.write(chaine objet.close( (g Modifier ce qui précède pour avoir, sur le même fichier, tous les élèves d une même année (2010, regroupés par lycée d origine. Les différents lycées seront séparés par une ligne, et annoncés par leur nom. Il faut enfermer tout ce qui précède dans une boucle sur les éléments de la listelycee. Il y a quelques difficultés : listelycee est une liste de tuple. Si on note lycee un de ces tuples, le nom d un lycée s obtient par lycee[0]. la requête de sélection est un peu pénible. On peut par exemple déporter son écriture dans une variable requête. Pour écrire une chaine sur plusieurs lignes, on utilise \ en Python : requete = "SELECT... " Les guillemets vont vous donner du fil à retordre 1 : soit on échappe, soit on ruse avec les guillemets simples ou doubles. Par exemple en rusant "WHERE (a.annee=2010 AND l.nom='" +lycee[0]+ "'" Il me semble plus simple d ouvrir et de fermer le fichier une unique fois. On peut avoir la même idée pour la base. Avec un peu plus d efforts, on obtiendrait non pas un seul fichier mais un fichier par lycée, sous une présentation un peu plus complète qu un simple CSV, et on enverrait automatiquement ce fichier au lycée concerné. 1. Là, pas de mascarade, on va voir qui comprend. À vous de briller. 9