Page 1 sur 1

[MySQL 4]LEFT JOIN et clause WHERE

Posté : 17 mars 2008, 20:32
par Rei Itchido
Bonjour à tous,

J'ai 3 tables : user, competition et user_competition.

Un user participe à 0..n competitions.
Une compétition a de 0...n users.
On retrouve dans user_competition user_id, competition_id et d'autres infos (classement, forfait etc...) avec uc_id comme clé primaire.

Code : Tout sélectionner

CREATE TABLE user ( user_id int(11) NOT NULL auto_increment, nom varchar(50) NOT NULL default '', PRIMARY KEY (user_id) ); CREATE TABLE competition ( competition_id int(11) NOT NULL auto_increment, nom varchar(50) NOT NULL default '', PRIMARY KEY (user_id) ); CREATE TABLE user_competition ( user_id int(11) NOT NULL default '0', competition_id int(11) NOT NULL default '0', forfait int(4) NOT NULL default '0', classement int(11) NOT NULL default '0', PRIMARY KEY (uc_id), UNIQUE KEY uk_1 (user_id, competition_id) );
Je cherche à récupérer la liste des users participant à certaines compétitions et le COUNT() de ces compétitions pour chaque user. Mais je cherche aussi à récupérer les users qui ne remplissent pas ces conditions (par exemple un user qui n'a participé à aucune compétition).

Par exemple, je veux récupérer pour chaque user le nombre de compétition auxquelles il a participé parmi les compétitions 1, 2 et 3 et pour lesquelles il n'a pas déclaré forfait.

Voilà la requête qui me semble logique

Code : Tout sélectionner

SELECT user.nom, COUNT(uc.uc_id) FROM user LEFT JOIN user_competition as uc ON user.user_id=uc.user_id WHERE uc.competition_id IN (1,2,3) AND uc.forfait=0 GROUP BY uc.user_id
Cette requête me permet de récupérer les users qui participent à ces competitions (ou aux moins à 1 des 3) sans être forfait mais pas ceux sans correspondances dans la table competition.

Dans la doc de MySQL il est mentionné qu'il faut faire un WHERE champs is null pour récupérer les ligne de la table de gauche sans correspondance à droite mais j'ai du mal à trouver la bonne syntaxe, je ne récupère pas ce que je veux.

Quelqu'un peut-il m'éclairer là-dessus?

Merci d'avance.

EDIT :

En fait en faisant :

Code : Tout sélectionner

SELECT user.nom, COUNT(uc.uc_id) FROM user LEFT JOIN user_competition as uc ON user.user_id=uc.user_id WHERE (uc.competition_id IN (1,2,3) OR uc.competition_id is null) AND (uc.forfait=0 OR uc.forfait is null) GROUP BY uc.user_id
je récupère à la fois les users inscrits à aucune compétition, les users qui sont inscrits à 1 des 3 compétitions du IN mais pas ceux qui sont inscrits à d'autres compétitions que ces 3 là. Ça me parait plutôt logique mais je ne récupère donc pas ce que je cherche.
Et là je sèche vraiment :?

Posté : 18 mars 2008, 05:52
par Patriboom
Et si ce n'était qu'une question de logique plutôt que de syntaxe.

Tu as:

Code : Tout sélectionner

SELECT user.nom, COUNT(uc.uc_id) FROM user LEFT JOIN user_competition as uc ON user.user_id=uc.user_id WHERE (uc.competition_id IN (1,2,3) OR uc.competition_id is null) AND (uc.forfait=0 OR uc.forfait is null) GROUP BY uc.user_id
Est-ce que cette formulation ressemblerait davantage à ce que tu cherches (j'avoue que je suis un peu mêlé dans tes souhaits et recherches).

Code : Tout sélectionner

SELECT user.nom, COUNT(uc.uc_id) FROM user LEFT JOIN user_competition as uc ON user.user_id=uc.user_id WHERE (uc.competition_id IN (1,2,3) AND uc.forfait=0 ) OR (uc.competition_id is null AND uc.forfait is null) GROUP BY uc.user_id
[/code]

Posté : 18 mars 2008, 07:50
par Hubert Roksor
Le problème avec cette requête, c'est que la condition de jointure est erronée. D'ailleurs, ça devient évident quand on relit attentivement le postulat de départ :
je veux récupérer pour chaque user le nombre de compétition auxquelles il a participé parmi les compétitions 1, 2 et 3 et pour lesquelles il n'a pas déclaré forfait.
Il y a 3 conditions de jointures, on devrait donc retrouver 3 conditions dans le LEFT JOIN

Code : Tout sélectionner

SELECT u.user_id, u.nom, COUNT(*) AS cnt FROM user u LEFT JOIN user_competition uc ON uc.user_id = u.user_id AND uc.competition_id IN (1, 2, 3) AND uc.forfait = 0 GROUP BY u.user_id
Un autre indicateur, c'est que la requête contient des "OR", mais sa description en français ne contient pas de "ou".

HTH