Précédent   Forum des professionnels en informatique > Bases de données > MySQL > Requêtes
Requêtes Forum d'entraide sur les requêtes MySQL
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 02/09/2010, 18h11   #1
Futur Membre du Club
 
Inscription : mai 2006
Messages : 49
Détails du profil
Informations personnelles :
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : mai 2006
Messages : 49
Points : 18
Points : 18
Par défaut Mauvaise compréhension de JOIN deux tables

Bonjour à tous,
J'ai un problème de compréhension sur les JOINTURE ou JOIN.
J'optimise actuellement mes requêtes et voici le problème:
Je cherche à savoir quels sont les enregistrements dans la table "mandats" dont la réf ne se trouvent pas dans la table "annonces".
La réponse est 2, mais j'obtiens une boucle de 716 réponses (soit 2 fois le nombre d'enr. de "annonces").

Pouvez-vous m'aider sur cette requête?
Code :
1
2
3
4
5
SELECT a.num_mdt,a.datmaj,a.contact 
FROM mandats a 
JOIN annonces b 
ON (a.num_mdt != b.ref) 
WHERE a.abonne='100' AND b.abonne='100' AND a.reprise = '0'
Merci d'avance.
devjcc est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/09/2010, 14h15   #2
ced
Rédacteur/Modérateur
 
Avatar de ced
 
Homme Cédric Duprez
Inscription : avril 2002
Messages : 3 776
Détails du profil
Informations personnelles :
Nom : Homme Cédric Duprez
Âge : 36
Localisation : France, Loiret (Centre)

Informations professionnelles :
Secteur : Agroalimentaire - Agriculture

Informations forums :
Inscription : avril 2002
Messages : 3 776
Points : 6 207
Points : 6 207
Bonjour,

Dans la requête que tu donnes, ce que tu fais, c'est une non-équijointure qui, pour chaque num_mdt va associer toutes les ref qui lui sont différentes.
En fait, pour obtenir ce que tu cherches, il faut plutôt faire comme ça :
Code :
1
2
3
4
5
6
SELECT a.num_mdt,a.datmaj,a.contact 
FROM mandats a 
LEFT JOIN annonces b ON a.num_mdt = b.ref 
WHERE a.abonne='100' 
AND a.reprise = '0'
AND b.ref IS NULL
ced
__________________
Rédacteur / Modérateur SGBD
Mes tutoriels et la FAQ MySQL

----------------------------------------------------
Pensez aux balises code et au tag
Je ne réponds pas aux questions techniques par message privé, les forums sont là pour ça
ced est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/09/2010, 15h14   #3
Futur Membre du Club
 
Inscription : mai 2006
Messages : 49
Détails du profil
Informations personnelles :
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : mai 2006
Messages : 49
Points : 18
Points : 18
Merci beaucoup de ta réponse.
En fait je n'ai précisé que dans la table "annonces" toutes les lignes ont une ref non nulle.
Je cherche a identifier quand "a.num_mdt" n'est pas égale à "b.ref" pour extraire "a.num_mdt"...
Peux-tu m'aider, j'ai tenté le code ci-dessous mais 0 réponse et j'en attends 2?
Code :
1
2
3
4
5
6
 
SELECT a.num_mdt,a.datmaj,a.contact 
FROM mandats a 
LEFT JOIN annonces b 
ON a.num_mdt = b.ref 
WHERE a.abonne='$id' AND b.abonne='$id' AND a.reprise = '0'
Merci
devjcc est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/09/2010, 15h56   #4
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur développement logiciels
Inscription : août 2006
Messages : 9 988
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Enseignement

Informations forums :
Inscription : août 2006
Messages : 9 988
Points : 16 202
Points : 16 202
Envoyer un message via MSN à CinePhil
Citation:
Envoyé par devjcc
Je cherche à savoir quels sont les enregistrements dans la table "mandats" dont la réf ne se trouvent pas dans la table "annonces".
La requête de Ced répond à ce besoin ! L'as-tu essayée ?

Citation:
Envoyé par devjcc
En fait je n'ai précisé que dans la table "annonces" toutes les lignes ont une ref non nulle.
Je cherche a identifier quand "a.num_mdt" n'est pas égale à "b.ref" pour extraire "a.num_mdt"...
La requête de Ced ne va pas chercher les annonces qui ont une référence nulle mais les cas où en face de la référence du mandat il n'y a aucune référence d'annonce.

LEFT JOIN retourne toutes les lignes de la table de gauche (ici, la table mandats) et donne la correspondance si elle existe dans la table de droite (ici, annonces). S'il n'y a pas de correspondance dans la table de droite, les colonnes de cette dernière afficheront NULL.

Et comme la requête cherche précisément ces NULL, le résultat est que la requête ne doit retourner que les numéros de mandats qui n'existent pas dans la colonne ref de la table des annonces.
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
À la maison comme au bureau, j'utilise Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/09/2010, 16h26   #5
Futur Membre du Club
 
Inscription : mai 2006
Messages : 49
Détails du profil
Informations personnelles :
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : mai 2006
Messages : 49
Points : 18
Points : 18
Bonjour CinePhil,
Citation:
Envoyé par CinePhil Voir le message
Et comme la requête cherche précisément ces NULL, le résultat est que la requête ne doit retourner que les numéros de mandats qui n'existent pas dans la colonne ref de la table des annonces.
Oui j'ai bien testé la requête de Ced, mais la réponse est 0 au lieu de 2.
Je ne comprend pas pourquoi le WHERE contient "b.ref IS NULL" dans la mesure ou ce champs n'est jamais NULL dans ma table.

Ma requete doit trouver si 'a.num_mdt' n'a aucune correspondance dans 'b.ref'.
En décomposant 2 requêtes, cela donnerait :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
 
# a remplacer par une requete JOIN sur les 2 tables
SELECT num_mdt,datmaj,contact FROM mandats WHERE abonne='$id' AND reprise = '0'
#... exec 
$j=$STH->rows;
	FOR ($i=0;$i<$j;$i++) {
	($ref,$datmaj,$contact)=$STH->fetchrow_array;
	$q="SELECT count(*) FROM annonces where abonne='$id' and ref='$ref'";
	$nb=$dbhI_mysql->selectrow_array($q);
 
		IF($nb>0 ) {print "pas de correspondance pour $ref";}
	}
J'espère que ma demande est plus claire.
Merci de ton aide.
devjcc est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/09/2010, 16h49   #6
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur développement logiciels
Inscription : août 2006
Messages : 9 988
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Enseignement

Informations forums :
Inscription : août 2006
Messages : 9 988
Points : 16 202
Points : 16 202
Envoyer un message via MSN à CinePhil
Citation:
Je ne comprend pas pourquoi le WHERE contient "b.ref IS NULL"
Je te l'ai expliqué juste au-dessus !

Soit la table A (a_id, a_libelle) et la table B (b_id, b_fk_id_A, b_nom) où b_fk_id_A est une clé étrangère faisant référence à l'identifiant a_id de la table A.

Dans A il y a ces lignes :
a_id / a_libelle
1 / MySQL
2 / Oracle
3 / Postgresql

Dans B il y a ces lignes :
b_id / b_fk_id_A / b_nom
1 / 1 / Bernard
2 / 1 / Michel
3 / 3 / Philippe

=> On voit que la valeur 2 n'existe pas pour la colonne b_fk_id_A.

Faisons-une jointure externe entre les deux tables :
Code :
1
2
3
4
SELECT A.a_id, A.a_libelle, 
  B.b_id, B.b_fk_id_A, B.b_nom
FROM A
LEFT OUTER JOIN B ON B.id_fk_id_A
=> Résultat :
a_id / a_libelle / b_id / b_fk_id_A / b_nom
1 / MySQL / 1 / 1 / Bernard
1 / MySQL / 2 / 1 / Michel
2 / Oracle / NULL / NULL / NULL
3 / Postgresql / 3 / 3 / Philippe

Tu vois les NULL ? Et pourtant toutes les lignes de B ont un b_fk_id_A !
Tu peux tester ça très facilement chez toi !

Donc si je veux connaître les a_id non présents dans B, il suffit d'ajouter à la requête précédente un WHERE qui recherche ces NULL !
Code :
1
2
3
4
5
SELECT A.a_id, A.a_libelle, 
  B.b_id, B.b_fk_id_A, B.b_nom
FROM A
LEFT OUTER JOIN B ON B.id_fk_id_A
WHERE B.bfk_id_A IS NULL
=> Résultat :
a_id / a_libelle / b_id / b_fk_id_A / b_nom
2 / Oracle / NULL / NULL / NULL
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
À la maison comme au bureau, j'utilise Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 08/09/2010, 17h25   #7
Futur Membre du Club
 
Inscription : mai 2006
Messages : 49
Détails du profil
Informations personnelles :
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : mai 2006
Messages : 49
Points : 18
Points : 18
re CinePhil,
Me revoici après de longs essais. J'ai du lire de nombreux tuto et en suivant tes conseils ci-dessus et ce tuto (http://sqlpro.developpez.com/cours/sqlaz/jointures/) je penses avoir compris
Ta solution n'a pas fonctionnée et je pense que le code ci-dessous est OK.
Il me donne actuellement les bons résultats après quelques tests.
Qu'en penses-tu?

Code :
1
2
3
4
5
6
 
SELECT a.num_mdt,a.datmaj,a.contact 
FROM mandats a 
LEFT OUTER JOIN annonces b 
ON b.ref=a.num_mdt AND a.abonne=b.abonne 
WHERE a.abonne='100' AND a.reprise='0' AND b.ref IS NULL
Si tu vois un défaut merci de me le faire savoir.
Merci encore.
devjcc 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 +1. Il est actuellement 06h48.


 
 
 
 
Partenaires

Hébergement Web