relations croisées entre tables

Invité
Invité n'ayant pas de compte PHPfrance

29 nov. 2007, 19:46

Bonjour à tous,

Une petite question sur l'organisation de tables pour mysql.
J'ai 2 tables, "élèves" et "matières" avec tout ce qu'il faut: id, noms, decriptifs....

Je dois afficher 2 listes distinctes à l'aide de php/html + requetes mysql : 1 liste des matières et une liste des élèves.

Un constat: un élève peut choisir plusieurs matières, une matière peut avoir plusieurs élèves

Mon problème:
- dans la liste des matières, il faut afficher tous les élèves inscrits pour chaque matière
- dans la liste des élèves, il faut afficher toutes les matières choisies pour chaque élève

J'ai du mal à voir quelle est la meilleure manière d'organiser la structure des tables pour arriver au bon résultat.

Faut-il 3 (ou peut être 4?) pour mapper les relations entre élèves et matières avec les id?
Ou alors 2 tables suffisent-elles?

Merci pour d'éventuels conseils sur la bonne marche à suivre pour ne pas avoir de pb par la suite.

Mammouth du PHP | 881 Messages

29 nov. 2007, 20:09

Pour être occupé à bâtir quelque chose du genre, je puis te dire qu'il m'est plus facile de travailler avec un troisième table que j'appelle "Inscription". Dans cette table, j'ai les champs "id_etudiant" et "id_cours" qui réfèrent aux autres tables. Aussi, dans la table "Inscriptions", j'en profite pour noter la date de l'inscription, date de complétion du cours, etc.

Dans une requête pour lister les étudiants, tu demanderas donc de sortir les inscriptions qui n'ont pas de date de complétion de cours avec des commandes comme JOIN ... ON .... GROUP BY

Ainsi aussi pour les listes des cours.
Soyez artisans de paix

Modérateur PHPfrance
Modérateur PHPfrance | 7636 Messages

29 nov. 2007, 20:18

En effet 3 tables pour le respect de la normalisation

/!\ Avant de poster se documenter et rechercher.
Qui ne sait pas rendre un service n'a pas le droit d'en demander.
MaBrute

Invité
Invité n'ayant pas de compte PHPfrance

29 nov. 2007, 20:22

et comment ça se passerait pour créer les formulaires qui permettent d'ajouter des matières ou des élèves à la base de données?

Je veux dire: quel type d'élément de formulaire mettre à disposition de l'admin pour qu'il puisse lier des élèves en créant une matière, et lier des matières en créant un profil élève?

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

29 nov. 2007, 21:08

D'une manière plus théorique, dans un MCD (modèle conceptuel de données), on parle de relation [n,m].
Cela correspond exactement à cette phrase :
un élève peut choisir plusieurs matières, une matière peut avoir plusieurs élèves
On peut donc dire qu'un élève peut avoir n matières et une matière peut avoir m élèves, voilà pourquoi une relation [n,m]

Au moment du passage du MCD au MPD (modèle physique de données), qui correspond au schéma de ta base, une relation [n,m] deviens une table.
Voilà donc pourquoi, si tu as ce genre de relation entre 2 tables, il te faut une table d'association ;)

edit : ça m'apprendre à contribuer à wikipedia avant de poster :?
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Invité
Invité n'ayant pas de compte PHPfrance

30 nov. 2007, 14:20

Merci pour les conseils.
Voici une tentative pour afficher dans la liste des matières, tous les élèves inscrits pour chaque matière.
Les tables
eleves => table des élèves
matieres => table des matieres
map_matieres_eleves =>table mappant les id des 2 tables précédentes.

Structure de map_matieres_eleves:
idmap => id autoincrement d'un couple idmatiere/ideleve
idmatiere => id de la matiere
ideleve => id de l'élève

Ma requete pour trouver les élèves correspondants, dans une boule foreach pour chaque matière:
foreach ($row as $matiere)
{
   $sql ="SELECT * FROM eleves AS a, map_matieres_eleves AS b WHERE b.idmatiere = $matiere->idmatiere";

....suite exécution requete + var_dump sur résultats
}
Le résultat:
1- Pas d'erreur => 0k
2- La requete pointe uniquement les matieres dont l'id est dans map_matieres_eleves => 0k

Le problème:
La liste des élèves pour chaque matière n'est pas cohérente. Les élèves affichés ne sont pas dans la table map_matieres_eleves, et ne devraient donc pas être affichés.

Voyez-vous ce que j'aurais pu oublier dans la requete?

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

30 nov. 2007, 14:51

Schéma plz http://www.phpfrance.com/forums/voir_sujet-34456.php

Tu n'as pas besoin d'un "idmap", ta clé primaire peut simplement se composer des deux colonnes.

Ta requête devrait ressembler à

Code : Tout sélectionner

SELECT * FROM map_matieres_eleves mme JOIN eleves e USING (ideleve) WHERE mme.idmatiere = ?

Invité
Invité n'ayant pas de compte PHPfrance

30 nov. 2007, 17:54

merci pour ta réponse. N'y aurait-il pas des "AS" qui manquent pour le nommage des tables?

Invité
Invité n'ayant pas de compte PHPfrance

30 nov. 2007, 18:02

hum, quelque chose ne va pas dans la requete, le résultat me renvoir NULL.

Invité
Invité n'ayant pas de compte PHPfrance

30 nov. 2007, 18:02

avec "AS" est sans "AS"

Invité
Invité n'ayant pas de compte PHPfrance

30 nov. 2007, 18:23

finalement j'ai pu obtenir le bon résultat avec un subselect en faisant ceci:
SELECT * FROM eleves WHERE ideleve IN (SELECT ideleve  FROM map_matieres_eleves WHERE idmatiere = $row->id)
ça marche très bien mais c'eset dommage, j'aurais bien voulu enfin comprendre comment marchent ces jointures qui me donnent des indigestions depuis longtemps.

Si quelqu'un a une idée sur la bonne manière de faire cela avec des jointures, je suis preneur!

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

30 nov. 2007, 18:46

comprendre comment marchent ces jointures
Un bon début serait de relire mon précédent post où je te rappelle de poster le schéma de tes tables (c'est un rappel qui est également afficher en rouge lors de l'envoi du message, où la procédure pour déboguer ses requêtes est expliquées) et de t'inscrire pour éviter de poster toutes les 30 secondes.