Select et limit en jointure

Eléphant du PHP | 52 Messages

21 juin 2008, 17:01

Bonjour,

J'ai 2 tables: users et picture.

Je souhaite selectionner tous les "username" dans users si une photo est présente dans picture.

username dans picture se nomme profile.

Code : Tout sélectionner

users,picture where picture.profile=users.username AND picture.main=1 AND picture.validated=1
La sélection m'affiche autant de fiche par 'username' que d'entrée dans 'picture' .
J'aimerai mettre une sorte de LIMIT en n'affichant qu'une seule fiche par username même si il y'a plusieurs entrées correspondantes a profile.

Une petite idée ? :shock:

Eléphant du PHP | 396 Messages

21 juin 2008, 17:24

Regarde du coté de GROUP BY

Eléphant du PHP | 52 Messages

21 juin 2008, 19:49

Ca ne fonctionne pas, qu'une seule fiche s'affiche.

Code : Tout sélectionner

picture.profile=users.username AND picture.main=1 AND picture.validated=1 GROUP BY picture.profile

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

22 juin 2008, 12:22

La commande GROUP BY sert lorsque l'on utilise des fonctions regroupant les résultats de plusieurs enregistrements (comme SUM, AVG, ...) pour lier les colonnes qui n'ont pas été groupées, donc à priori rien à voir ici.

Le LIMIT n'aura pas plus d'effet ici, puisque celui-ci se contente de limiter le nombre d'enregistrement retournés par la requête, mais n'affecte en rien les résultats de celle-ci.

Normalement dans ton cas, une simple jointure entre tes deux tables doit suffir, et un

Code : Tout sélectionner

SELECT users.username FROM users, picture WHERE picture.profile=users.username
devrait déjà ne te retourner que les username pour lesquels une correspondance a été trouvée dans la table picture.

Si tel n'est pas le cas, donne nous la structure des deux tables (les create table) et la requête complète...
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Eléphant du PHP | 52 Messages

22 juin 2008, 15:47

Ca ne fonctionne pas.

Voici la requête, ou plutôt une partie car celle ci est découpée en plusieurs options de recherche. Pas facile de s'y retrouver.

Code : Tout sélectionner

SELECT * from users,picture where picture.profile=users.username AND picture.main=1 AND picture.validated=1
La table users

Code : Tout sélectionner

CREATE TABLE `users` ( `username` varchar(70) NOT NULL default '', `email` varchar(255) default NULL, `password` varchar(70) default NULL, `ipaddress` varchar(30) default NULL, `joined` int(11) default '0', `lastlogin` int(11) default NULL, `expire_date` int(11) default NULL, `completed_profile` int(11) default '0', `pay_upload` smallint(6) default '0', `pay_contact` smallint(6) default '0', `pay_webchat` smallint(6) default '0', `pay_gb` smallint(6) default '0', `pay_rotate` smallint(6) default '0', `pay_visitor` smallint(6) default '0', `pay_fav` smallint(6) default '0', `pay_match` smallint(6) default '0', `pay_flirts` smallint(6) default '0', `delete_me` int(11) default '0', `f_1` smallint(6) default NULL, `f_2` varchar(255) default NULL, `f_4` smallint(6) default NULL, `f_3` smallint(6) default NULL, `f_5` smallint(6) default NULL, `lookingf_1` smallint(6) default NULL, `lookingf_3` smallint(6) default NULL, `f_6` smallint(6) default NULL, `lookingf_6` varchar(255) default NULL, `betweenFromf_6` varchar(255) default NULL, `betweenTof_6` varchar(255) default NULL, `lookingf_2` varchar(255) default NULL, `betweenFromf_2` varchar(255) default NULL, `betweenTof_2` varchar(255) default NULL, `f_7` smallint(6) default NULL, `f_8` smallint(6) default NULL, `f_9` smallint(6) default NULL, `f_10` varchar(255) default NULL, `f_11` varchar(255) default NULL, `f_12` smallint(6) default NULL, `lookingf_12` varchar(255) default NULL, `f_13` text, `f_14` varchar(255) default NULL, `f_15` smallint(6) default NULL, `f_16` smallint(6) default NULL, `f_17` varchar(255) default NULL, `f_18` text, `visits` int(11) default '0', `validated` int(11) default NULL, `video` varchar(190) default NULL, `notify_flirts` smallint(6) default '1', `notify_localmsg` smallint(6) default '2', `notify_important` tinyint(4) default '2', `f_23` smallint(6) default NULL, `lookingf_23` smallint(6) default NULL, `f_25` smallint(6) default NULL, `lookingf_25` smallint(6) default NULL, `betweenFromf_3` smallint(6) default NULL, `betweenTof_3` smallint(6) default NULL, `betweenFromf_23` smallint(6) default NULL, `betweenTof_23` smallint(6) default NULL, PRIMARY KEY (`username`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
La table picture:

Code : Tout sélectionner

CREATE TABLE `picture` ( `id` int(4) NOT NULL auto_increment, `profile` varchar(50) default NULL, `filename` varchar(50) default NULL, `filesize` varchar(50) default NULL, `filetype` varchar(50) default NULL, `imagew` varchar(10) default NULL, `imageh` varchar(10) default NULL, `main` int(1) default '0', `validated` int(1) default '0', `descr` varchar(255) default NULL, `points` int(11) default '0', `voters` int(11) default '0', `grade` double(3,2) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=707 DEFAULT CHARSET=utf8 AUTO_INCREMENT=707 ;

Eléphant du PHP | 377 Messages

22 juin 2008, 19:13

Code : Tout sélectionner

SELECT users.username FROM users, picture WHERE picture.profile=users.username
à première vue je vois deux problèmes dans ce code : d'abord je mettrais les conditions de jointure dans le "ON" et pas dans le "WHERE", mais ça...
ensuite, si un user a posté plusieurs photos, il va ressortir plusieurs fois
donc je dirais :

Code : Tout sélectionner

SELECT DISTINCT username FROM users LEFT JOIN picture ON picture.profile=users.username
Petit scarabée deviendra grand

Eléphant du PHP | 52 Messages

22 juin 2008, 20:38

Code : Tout sélectionner

SELECT DISTINCT username FROM users LEFT JOIN picture ON picture.profile=users.username
Cela sélectionne tous les 'username'. Je souhaite uniquement ceux qui ont une photo :) .

Eléphant du PHP | 377 Messages

23 juin 2008, 10:01

Dans ce cas :

Code : Tout sélectionner

SELECT DISTINCT username FROM users LEFT JOIN picture ON picture.profile=users.username WHERE picture.id IS NOT NULL
Petit scarabée deviendra grand

Eléphant du PHP | 396 Messages

23 juin 2008, 10:16

Avec l'utilisation de LEFT JOIN on n'est pas sensé récupérer uniquement les lignes qui ont une correspondance justement? :-k
Sans le WHERE IS NOT NULL j'entends

Eléphant du PHP | 377 Messages

23 juin 2008, 12:05

j'aurais dit pareil... maintenant j'ai répondu avec la tête dans le ***
Donc je ne vois vraiment pas ce qui cloche :-k
Petit scarabée deviendra grand

Eléphant du PHP | 175 Messages

23 juin 2008, 12:24

Avec l'utilisation de LEFT JOIN on n'est pas sensé récupérer uniquement les lignes qui ont une correspondance justement? :-k
Sans le WHERE IS NOT NULL j'entends
Non justement, c'est l'interet du left join ;)
S'il y a une ligne dans A qui répond à la clause WHERE, mais qu'il n'y avait aucune ligne dans B qui répondait à la condition du LEFT JOIN, alors une ligne supplémentaire de B est générée avec toutes les colonnes mises à NULL.
src: http://dev.mysql.com/doc/refman/5.0/fr/ ... ation.html

Eléphant du PHP | 52 Messages

23 juin 2008, 13:23

Code : Tout sélectionner

SELECT DISTINCT username FROM users LEFT JOIN picture ON picture.profile=users.username WHERE picture.id IS NOT NULL
Le nombre d'username semble correspondre (fichier test). Mais, il y'a un hic. Lorsque j'intègre la requête à mon script j'ai des 'username' en doublon... Autant d'username affiché que d'entrées dans picture.
if (getParam("pic_only",""))
{
	if ($set_validate_on)
		$addOnSQL.=" AND picture.profile=users.username AND picture.main=1 AND picture.validated=1";
	else 
		$addOnSQL.=" AND picture.profile=users.username AND picture.main=1";
	
	$addOnSQL.=$sql;
	$addOnParams.="&pic_only=1&";		
}
dans mon fichier de fonctions:
 	if (isset($_GET["pic_only"]))
 		$sql = "SELECT * from users,picture where (";
 	else 
 		$sql = "SELECT * from users where (";
En fait, pour faire simple, il faudrait que je change uniquement la fin de la requête.

Nota: validate est sur on

Eléphant du PHP | 396 Messages

23 juin 2008, 13:48

Et le DISTINCT?

Eléphant du PHP | 377 Messages

23 juin 2008, 14:02

if (isset($_GET["pic_only"])) 
         $sql = "SELECT * from users,picture where ("; 
     else  
         $sql = "SELECT * from users where (";
Je sais je radote :oops: mais tu fais un produit cartésien de tes deux tables, tu vas écrouler ton serveur
pars sur :
if (isset($_GET["pic_only"])) 
         $sql = "SELECT * from users LEFT JOIN picture ON users.id=picture.profile where ( "; 
     else  
         $sql = "SELECT * from users where (";
Et dans ce cas là, étant donné que tu vas rajouter un "AND picture.main=1 AND picture.validated=1", le "IS NOT NULL" est implicite, tu n'en as donc plus besoin

Et comme le fait remarquer Rei Itchido, ne pas oublier le distinct ;)
Petit scarabée deviendra grand

Eléphant du PHP | 52 Messages

23 juin 2008, 18:04

Ca fonctionne :D

Un grand merci à tout le monde. Voilà ce qui fonctionne sur mon serveur:
 	if (isset($_GET["pic_only"]))
 		$sql = "SELECT DISTINCT username, f_13, f_2, f_12, f_1 FROM users LEFT JOIN picture ON picture.profile=users.username WHERE (";
 	else 
 		$sql = "SELECT * from users where (";
J'ai du remplacer * par username, f_13, f_2, f_12, f_1 . Bizzarement, le * affiche des doublons et donc fausse les résultats. Va comprendre :shock: .