Précédent   Forum des professionnels en informatique > PHP > PHP & SGBD
PHP & SGBD Forum d'entraide sur les SGBD avec PHP. Avant de poster : FAQ BDD, toutes les FAQ PHP, cours BDD et sources BDD
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 10/08/2006, 16h55   #1
Nouveau Membre du Club
 
Avatar de kiruban
 
Inscription : août 2005
Messages : 121
Détails du profil
Informations forums :
Inscription : août 2005
Messages : 121
Points : 39
Points : 39
Par défaut [SQL] Optimiser une jointure dans PHP

Bonjour,

Je voudrais optimisé mon code, quelqu'un peut m'aider et donné des suggestions.
Citation:
$querychamp = mysql_query("SELECT * FROM gagnant",$db);
$num = mysql_num_rows($querychamp);
if ( $num != 0) {
while ( $gagnant = mysql_fetch_array($querychamp) ) {
$gagnantid = $gagnant['id'];
$cadeauxid = $gagnant['cadeaux'];
$membreid = $gagnant['gagnant'];
$date_mysql = $gagnant['date'];
$date = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3-$2-$1', $date_mysql);
$time = $gagnant['time'];
$querychamp2 = mysql_query("SELECT * from membre WHERE id_membre = $membreid",$db);
while ( $membre = mysql_fetch_array($querychamp2) ) {
$nom = $membre['nom'];
$prenom = $membre['prenom'];
echo strtoupper(substr($nom,0,1)).
strtolower(substr($nom,1)).' '.
strtoupper(substr($prenom,0,1)).'.';
}
$querychamp3 = mysql_query("SELECT * from jeuxcompteur WHERE id = $cadeauxid",$db);
while ( $cadeau = mysql_fetch_array($querychamp3) ) {
$titre = $cadeau['titre'];
echo " à gagné(e) au jeu *$titre* le $date à $time ";
}
echo "<br>";
}
} else {
echo "Il n'y a pas de cadeaux gagnés.";
}
merci beaucoup,
__________________
Knowledge is useless until you share it.
kiruban est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/08/2006, 17h55   #2
Membre régulier
 
Avatar de titoon
 
Inscription : janvier 2005
Messages : 71
Détails du profil
Informations personnelles :
Localisation : France, Nord (Nord Pas de Calais)

Informations forums :
Inscription : janvier 2005
Messages : 71
Points : 84
Points : 84
Si j'ai bien compris le schéma de ta base, tu peux utiliser comme requête :
Code :
1
2
3
4
5
 
SELECT * // attention aux champs "id" communs à gagnant et jeuxcompteur
FROM gagnant g, membre m, jeuxcompteur j
WHERE g.gagant = m.id_membre // jointure gagnant <=> membre
AND g.cadeau = j.jeucompteur // jointure cadeau <=> jeuxcompteur
titoon est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/08/2006, 18h27   #3
Rédacteur

 
Inscription : septembre 2002
Messages : 1 591
Détails du profil
Informations personnelles :
Âge : 36

Informations forums :
Inscription : septembre 2002
Messages : 1 591
Points : 3 108
Points : 3 108
Citation:
Envoyé par titoon
Si j'ai bien compris le schéma de ta base, tu peux utiliser comme requête :
Code :
1
2
3
4
5
 
SELECT * // attention aux champs "id" communs à gagnant et jeuxcompteur
FROM gagnant g, membre m, jeuxcompteur j
WHERE g.gagant = m.id_membre // jointure gagnant <=> membre
AND g.cadeau = j.jeucompteur // jointure cadeau <=> jeuxcompteur
C'est indépendant du PHP et plutôt lié directement au forum "langage SQL". Ceci dit, je ne pense pas que cette requête ci-dessus soit si optimale, pour les raisons suivantes:

1. SELECT *, dans la mesure du possible, il faut toujours essayer d'éviter le "*" sauf si on a réellement besoin de rappatrier toutes les colonnes.
2. Il faut préférer les mots clés de jointure tels que INNER JOIN, LEFT JOIN, RIGHT JOIN, etc...plutôt que d'effectuer celles-ci dans la clause WHERE. Théoriquement, la clause WHERE est réservée aux critères uniquement.

Ceci dit, loin de moi de vouloir distribuer les bons points, donc, fais comme tu le sens
stephane eyskens est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/08/2006, 18h47   #4
Nouveau Membre du Club
 
Avatar de kiruban
 
Inscription : août 2005
Messages : 121
Détails du profil
Informations forums :
Inscription : août 2005
Messages : 121
Points : 39
Points : 39
moi j'utilise toujours '*' mais quelles sont les risques d'utiliser celui-ci ?
__________________
Knowledge is useless until you share it.
kiruban est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/08/2006, 19h09   #5
Rédacteur

 
Inscription : septembre 2002
Messages : 1 591
Détails du profil
Informations personnelles :
Âge : 36

Informations forums :
Inscription : septembre 2002
Messages : 1 591
Points : 3 108
Points : 3 108
Citation:
Envoyé par kiruban
moi j'utilise toujours '*' mais quelles sont les risques d'utiliser celui-ci ?
Toutes les colonnes de ta table sont rappatriées, donc plus de trafic sur le réseau, en RAM etc....Si par exemple tu as une table ayant cette structure

Citation:
Table Clients

ID_Client
Nom
Prenom
Titre
DateNaissance
NumIdentite
ID_Addr
Commentaire
....
Et que tu as une portion de code qui sert à afficher uniquement les nom, prénom et titre

Tu devrais théoriquement faire

SELECT Nom,Prenom,Titre FROM Clients....

Seules les informations liées à ces colonnes te seront renvoyées par le SGBD. Tu réduiras du même coup le trafic réseau et ton traitement côté PHP sera lui aussi plus rapide car moins de données.

D'autre part, cette manière de travailler est beaucoup plus parlante dans le code car :

- Tu sais exactement ce dont tu as besoin
- Le fait de nommer explicitement les colonnes te renseigne déjà sur la structure de ta table.
- Si un jour, tu modifies ta table et que tu ajoutes un champ pour usage interne qui ne devrait jamais être affiché, en utilisant "*", tu rappatrieras à chaque fois la valeur de ce champ inutilement.
stephane eyskens est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/08/2006, 19h15   #6
Nouveau Membre du Club
 
Avatar de kiruban
 
Inscription : août 2005
Messages : 121
Détails du profil
Informations forums :
Inscription : août 2005
Messages : 121
Points : 39
Points : 39
Citation:
Envoyé par titoon
Si j'ai bien compris le schéma de ta base, tu peux utiliser comme requête :
Code :
1
2
3
4
5
 
SELECT * // attention aux champs "id" communs à gagnant et jeuxcompteur
FROM gagnant g, membre m, jeuxcompteur j
WHERE g.gagant = m.id_membre // jointure gagnant <=> membre
AND g.cadeau = j.jeucompteur // jointure cadeau <=> jeuxcompteur
j'ai essayer
Citation:
$querychamp = mysql_query("SELECT *
FROM gagnant g, membre m, jeuxcompteur j
WHERE g.gagnant = m.id_membre
AND g.cadeaux = j.id",$db);
while ( $data = mysql_fetch_array($querychamp) ) {
print_r($data);
$gagnantid = $gagnant['id'];
$cadeauxid = $gagnant['cadeaux'];
$membreid = $gagnant['gagnant'];
$date_mysql = $gagnant['date'];
$date = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3-$2-$1', $date_mysql);
$time = $gagnant['time'];
$nom = $membre['nom'];
$prenom = $membre['prenom'];
$titre = $cadeau['titre'];
echo strtoupper(substr($nom,0,1)).
strtolower(substr($nom,1)).' '.
strtoupper(substr($prenom,0,1)).'.';
echo " à gagné(e) au jeu *$titre* le $date à $time <br>";
}
vous pouvez me dire comment l'affichez car la ça ne marche pas
__________________
Knowledge is useless until you share it.
kiruban est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/08/2006, 19h23   #7
Nouveau Membre du Club
 
Avatar de kiruban
 
Inscription : août 2005
Messages : 121
Détails du profil
Informations forums :
Inscription : août 2005
Messages : 121
Points : 39
Points : 39
Citation:
$querychamp = mysql_query("SELECT date, time, nom, prenom, titre
FROM gagnant g, membre m, jeuxcompteur j
WHERE g.gagnant = m.id_membre
AND g.cadeaux = j.id",$db);
while ( $data = mysql_fetch_array($querychamp) ) {
$date_mysql = $data['date'];
$date = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3-$2-$1', $date_mysql);
$time = $data['time'];
$nom = $data['nom'];
$prenom = $data['prenom'];
$titre = $data['titre'];
echo strtoupper(substr($nom,0,1)).
strtolower(substr($nom,1)).' '.
strtoupper(substr($prenom,0,1)).'.';
echo " à gagné(e) au jeu *$titre* le $date à $time <br>";
}
c'est bon ça marche, vous pouvez me dire plus sur l'utilisation du INNER JOIN, LEFT JOIN, RIGHT JOIN, etc.. et montré une démonstration

merci beaucoup

PS: par rapport à ce que j'avais au début à maintenant j'ai perdu beaucoup de ligne en gardant le meme résultat
__________________
Knowledge is useless until you share it.
kiruban est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/08/2006, 10h40   #8
Membre régulier
 
Avatar de titoon
 
Inscription : janvier 2005
Messages : 71
Détails du profil
Informations personnelles :
Localisation : France, Nord (Nord Pas de Calais)

Informations forums :
Inscription : janvier 2005
Messages : 71
Points : 84
Points : 84
Citation:
Envoyé par stephane eyskens
1. SELECT *, dans la mesure du possible, il faut toujours essayer d'éviter le "*" sauf si on a réellement besoin de rappatrier toutes les colonnes.
2. Il faut préférer les mots clés de jointure tels que INNER JOIN, LEFT JOIN, RIGHT JOIN, etc...plutôt que d'effectuer celles-ci dans la clause WHERE. Théoriquement, la clause WHERE est réservée aux critères uniquement.
OK pour le select *, perso je l'utilise jamais.

Par contre, pour le second point... t'as une doc là dessus ???

Citation:
Envoyé par http://dev.mysql.com/doc/refman/5.0/fr/join.html
INNER JOIN et , (virgule) sont sémantiquement équivalents. Les deux opèrent une jointure totale sur les tables utilisées. Normalement, vous spécifiez les conditions de jointure dans la clause WHERE.
Citation:
Envoyé par kiruban
c'est bon ça marche, vous pouvez me dire plus sur l'utilisation du INNER JOIN, LEFT JOIN, RIGHT JOIN, etc.. et montré une démonstration
Tu trouveras ton bonheur dans la doc de mysql
titoon est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/08/2006, 13h38   #9
Rédacteur

 
Inscription : septembre 2002
Messages : 1 591
Détails du profil
Informations personnelles :
Âge : 36

Informations forums :
Inscription : septembre 2002
Messages : 1 591
Points : 3 108
Points : 3 108
Citation:
Envoyé par titoon
OK pour le select *, perso je l'utilise jamais.
Par contre, pour le second point... t'as une doc là dessus ???
Tu peux par exemple aller voir sur sql.developpez.com
stephane eyskens est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/08/2006, 15h11   #10
Membre habitué
 
Inscription : octobre 2003
Messages : 102
Détails du profil
Informations personnelles :
Âge : 39

Informations forums :
Inscription : octobre 2003
Messages : 102
Points : 108
Points : 108
Salut,

je rajouterais que de nommer uniquement les champs dont on a besoin permet d'utilser mysql_fetch_row() (le plus économique de la famille des fetch) plus facilement car on n'a pas forcement en tete la position ordinale des champs de sa tables.

Quand au JOIN déja, il est issu de la norme SQL99 qui était venu remplacer la norme SQL92.
Il est donc plus au gout du jour, plus clair entant qu'il confère une syntaxe explicite et dédiée aux jointures en les séparant du reste de la clause WHERE.
En plus Il permet souvent l'economie des alias qui la surchargent.
Et surtout plus puissant que les jointures en clause where.
JE ne vais pas me répéter je vous renvoie a ce topic ou je donne quelques exemples simples.
http://www.developpez.net/forums/sho...d.php?t=191918 (message #8)

Sinon ben voila la version JOIN du présent problème (je part du principe qu'aucun nom de champ sité dans la requete n'est commun à 2 tables =>aucun d'alias)
J'ai changé l'ordre d'apparition des tables, afin de pouvoir enfiler les tables comme des perles dans ma requete (on commence toujours par une table a l'extrémité pour pouvoir enchainer les JOIN):
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
$querychamp = mysql_query("SELECT date, time, nom, prenom, titre 
FROM membre JOIN gagnant on(id_membre=gagnant)
JOIN jeuxcompteur ON (cadeaux=id)",$db);
while ( $data = mysql_fetch_array($querychamp) ) {
$date_mysql = $data['date'];
$date = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3-$2-$1', $date_mysql);
$time = $data['time'];
$nom = $data['nom'];
$prenom = $data['prenom'];
$titre = $data['titre'];
echo strtoupper(substr($nom,0,1)).
strtolower(substr($nom,1)).' '.
strtoupper(substr($prenom,0,1)).'.';
echo " à gagné(e) au jeu *$titre* le $date à $time <br>";
}
__________________
il n'y a pas de sotte existence
gisele est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/08/2006, 17h15   #11
Membre régulier
 
Avatar de titoon
 
Inscription : janvier 2005
Messages : 71
Détails du profil
Informations personnelles :
Localisation : France, Nord (Nord Pas de Calais)

Informations forums :
Inscription : janvier 2005
Messages : 71
Points : 84
Points : 84
Erf, désolé, je suis en mysql 3.32.58, et cette version semble ne pas connaitre le JOIN seul... Je ne sais pas comment il se comporte (équivalent de LEFT JOIN ?)

Code :
1
2
3
4
5
6
 
mysql> SELECT date, time, nom, prenom, titre
    -> FROM membre JOIN gagnant ON (id_membre = gagnant)
    -> JOIN jeuxcompteur ON (cadeaux = id);
ERROR 1064: You have an error in your SQL syntax near 'ON (id_membre = gagnant)
JOIN jeuxcompteur ON (cadeaux = id)' at line 2
titoon est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/08/2006, 17h56   #12
Membre habitué
 
Inscription : octobre 2003
Messages : 102
Détails du profil
Informations personnelles :
Âge : 39

Informations forums :
Inscription : octobre 2003
Messages : 102
Points : 108
Points : 108
Salut,

effectivement essaye ca:
Code :
1
2
3
4
5
 
SELECT date, time, nom, prenom, titre 
FROM membre LEFT JOIN gagnant on(id_membre=gagnant)
AND gagnant IS NOT NULL
LEFT JOIN jeuxcompteur ON (cadeaux=id)
la condition is not null, permet a la requete de ne pas remonter également des lignes d'utilisateur qui n'ont pas gagné, (les champs correspondant a la table gagnant seraient comblés a null).

tu comprendras visuellement la finesse du LEFT JOIN en essayant d'abord sans le "AND gagnant IS NOT NULL " et ensuite avec.
la différence entre les retours te permettra de comprendre l'interet de jouer avec les LEFT JOIN et RIGHT JOIN.
__________________
il n'y a pas de sotte existence
gisele est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 05h02.


 
 
 
 
Partenaires

Hébergement Web