Page 1 sur 1

requête dans une seule table

Posté : 30 oct. 2006, 16:26
par mcorgnet
Bonjour,

j'ai une table qui a pour champs :

id, nom, parentId (ça suffira pour ce que je veux). Elle liste des utilisateurs. Elle est liée à elle même. quelques données :

id nom parentId
1 mathieu 3
2 frank 3
3 invités 0
4administrateurs 0
5 jean 4

Bref, je voudrais pouvoir ressortir tous les résultats avec les liens entre les objets parents et enfants.

Ca peut se faire ?

Posté : 30 oct. 2006, 16:51
par Cyrano
Il faut faire une auto-jointure, donc virtuellement créer une copie de la table pour la joindre avec son original :

Il y a toutefois un problème avec ton jeu d'essai :

Code : Tout sélectionner

+----+-----------------+----------+ | id | nom | parentId | +----+-----------------+----------+ | 1 | mathieu | 3 | | 2 | frank | 3 | | 3 | invités | 0 | | 4 | administrateurs | 0 | | 5 | jean | 4 | +----+-----------------+----------+
Comment as-tu pu déterminer la valeur de l'identifiant parent des lignes 1 et 2 puisque l'identifiant "3" n'existait pas ? :-k

Je propose de partir du même jeu revu et corrigé suivant :

Code : Tout sélectionner

+----+-----------------+----------+ | id | nom | parentId | +----+-----------------+----------+ | 1 | administrateurs | 0 | | 2 | invités | 0 | | 3 | mathieu | 2 | | 4 | frank | 2 | | 5 | jean | 1 | +----+-----------------+----------+
Nous devons alors obtenir en sortie le tableau suivant :

Code : Tout sélectionner

+-----------------+---------+ | parent | enfant | +-----------------+---------+ | administrateurs | jean | | invités | mathieu | | invités | frank | +-----------------+---------+
Peux-tu confirmer que c'est bien ce que tu veux obtenir ?

Posté : 30 oct. 2006, 16:53
par mcorgnet
vouiiiiiiiiiiiiiiiii


mais comment ?

en fait, quand je crée un utilisateur, je crée une ligne vide. C'est pour ça qu'un utilisateur peut être créé avant un groupe, et y être associé plus tard.

Ca m'évite de faire des contrôles de partout, de gérer des insert et des update à foison. Je gère uniquement les update, en fait.

Posté : 30 oct. 2006, 17:09
par Cyrano
Alors deux options, la première :

Code : Tout sélectionner

mysql> SELECT i1.`nom` AS Parents, i2.`nom` AS enfants -> FROM `inscrits` AS i1, `inscrits` AS i2 -> WHERE i1.`id` = i2.`parentId` -> AND i2.`id` <> 0 -> ORDER BY i1.`id`; +----------------+---------+ | Parents | enfants | +----------------+---------+ | Administrateur | Jean | | Invites | Franck | | Invites | Mathieu | +----------------+---------+ 3 rows in set (0.01 sec)
La seconde possibilité va sortir tout même si un parent n'a pas d'enfants :

Code : Tout sélectionner

mysql> SELECT i1.`nom` AS Parents, i2.`nom` AS enfants -> FROM `inscrits` AS i1 -> LEFT JOIN `inscrits` AS i2 -> ON i1.`id` = i2.`parentId` -> AND i2.`id` <> 0 -> ORDER BY i1.`id`; +----------------+---------+ | Parents | enfants | +----------------+---------+ | Administrateur | Jean | | Invites | Mathieu | | Invites | Franck | | Mathieu | NULL | | Franck | NULL | | Jean | NULL | +----------------+---------+ 6 rows in set (0.02 sec)

Posté : 30 oct. 2006, 17:10
par Vikchill
Ca m'évite de faire des contrôles de partout, de gérer des insert et des update à foison. Je gère uniquement les update, en fait.
Et maintenant tu découvres le revers de la médaille? :P

Posté : 30 oct. 2006, 17:14
par mcorgnet
absolument pas en fait. C'est juste que je suis infoutu de lier des champs dans une même table.

En l'occurence, quand je travaille avec les utilisateurs, ils apprécient avoir la possibilité de cliquer sur un bouton : "nouvel objet", limite de le faire plusieurs fois, et de remplir ensuite les champs de chaque objet.

Il n'y a pas vraiment de revers à la médaille, en fait. Je gagne du temps, mon code est plus léger, plus propre, la base de données est à peine plus solicitée, et je me permets de passer plus de temps sur la sécurité des données envoyées, du coup.

Enfin si tu vois des points négatifs que je devrais souligner, ça m'intéresse, auquel cas je ne suis pas contre revoir ma position. Pour l'instant, et pour avoir essayé les deux méthodes, celle ci m'apparaît nettement plus efficace.

Evidemment, derrière, je gère de quoi supprimer les enregistrements vides (tous ceux qui ont plus de 24 heures, et qui n'ont jamais connu de modification).

Posté : 30 oct. 2006, 17:17
par Cyrano
Tiens, j'ajoute une version de la première option proposée en utilisant un JOIN :

Code : Tout sélectionner

mysql> SELECT i1.`nom` AS Parents, i2.`nom` AS enfants -> FROM `inscrits` AS i1 -> LEFT JOIN `inscrits` AS i2 -> ON i1.`id` = i2.`parentId` -> WHERE i1.`parentId` = 0 -> ORDER BY i1.`id`; +----------------+---------+ | Parents | enfants | +----------------+---------+ | Administrateur | Jean | | Invites | Mathieu | | Invites | Franck | +----------------+---------+ 3 rows in set (0.00 sec)

Posté : 30 oct. 2006, 17:18
par mcorgnet
C'est un génie notre cyrano.

Si t'étais pas un homme, j't'épouserais.

ça m'ferait gagner pas mal de temps en dev' ...

Posté : 30 oct. 2006, 17:19
par Cyrano
Pas de quoi ;)