Problème de clé étrangère [RESOLU]

Problème de clé étrangère [RESOLU] - SQL/NoSQL - Programmation

Marsh Posté le 11-06-2009 à 16:25:53    

Bonjour  [:maxmaker] ,
 
J'ai un problème avec une requête SQL. Je voudrais avoir un résultat qui nécessite de passer par 2 tables et donc d'avoir une clé étrangère.
 
Présentation de mes tables.
 

CREATE TABLE utilisateur  
(
  id_util int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  nom_util varchar(20) NOT NULL,
  prenom_util varchar(20) NOT NULL,
  login varchar(20) NOT NULL,
  pass varchar(20) NOT NULL,
  statut varchar(25) NOT NULL,
  FOREIGN KEY (statut) REFERENCES statut (id_statut)
);



CREATE TABLE statut
(
  id_statut int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  intitule_statut varchar(20) NOT NULL
);


Ma requête est toute simple  [:getalife]  
 


SELECT nom_util, prenom_util, intitule_statut
FROM statut, utilisateur
WHERE utilisateur.statut = statut.id_statut;


 
Quand je fais ça dans PhpMyAdmin la requête ne me renvois aucun résultat alors que ces colonnes sont remplis.
Y aurait-il une explication toute simple et logique à ce mystérieux problème qui m'empêche de dormir ?  [:doc petrus]  
 
Merci  [:pseudoman]


Message édité par Profil supprimé le 16-06-2009 à 11:05:02
Reply

Marsh Posté le 11-06-2009 à 16:25:53   

Reply

Marsh Posté le 11-06-2009 à 17:36:31    

D'un coté le champ "statut" de ta table "utilisateur" est un varchar de longueur 25, et de l'autre le champ id_statut de ta table "statut" est un int de longueur 11.
Sachant que l'un est une clé étrangère de l'autre, tu n'as pas l'impression d'une petite incohérence là ?


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 11-06-2009 à 17:39:31    

Le problème est que la jointure est faîte sur des données qui ne sont pas de même type :
utilisateur.statut est un varchar2, alors que statut.id_statut est un entier. Il faudrait juste rajouter une fonction de conversion. En Oracle, on ferait WHERE utilisateur.statut = to_char(statut.id_statut); ou WHERE to_number(utilisateur.statut) = statut.id_statut;. Mais je ne connais pas la syntaxe MySQL par coeur.

Reply

Marsh Posté le 11-06-2009 à 17:40:43    

olivthill a écrit :

Le problème est que la jointure est faîte sur des données qui ne sont pas de même type :
utilisateur.statut est un varchar2, alors que statut.id_statut est un entier. Il faudrait juste rajouter une fonction de conversion. En Oracle, on ferait WHERE utilisateur.statut = to_char(statut.id_statut); ou WHERE to_number(utilisateur.statut) = statut.id_statut;. Mais je ne connais pas la syntaxe MySQL par coeur.


Il faudrait surtout qu'il mette les mêmes types sur les 2 champs !


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 11-06-2009 à 18:51:19    

Ah oui exact, je viens de rectifier ça. Par contre PhPMyadmin m'indique toujours 0 résultat.

Reply

Marsh Posté le 11-06-2009 à 21:05:23    

Et avec une jointure externe, tu obtiens des résultats ?


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 11-06-2009 à 21:17:31    

Je...sais pas faire de jointures externe  :sweat:  
 
J'vais voir la tronche que ça a.

Reply

Marsh Posté le 11-06-2009 à 22:40:53    

LEFT JOIN
D'ailleurs tu devrais employer la syntaxe INNER JOIN au lieu de faire des jointures "à l'ancienne" avec WHERE, c'est plus correct


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 12-06-2009 à 10:47:18    

Alors, j'ai essayé avec INNER JOIN et il m'envoie sur les roses, j'ai aussi essayé en changeant le moteur MyISAM par InnoDB mais rien n'y fait.
Par contre j'ai pas essayé avec LEFT JOIN.
 
 
 :sweat:

Reply

Marsh Posté le 12-06-2009 à 11:22:36    

Comment ça le "INNER JOIN m'envoie sur les roses" ? C'est quoi le message d'erreur ? Tu as utilisé la bonne syntaxe ?

Code :
  1. SELECT nom_util, prenom_util, intitule_statut
  2. FROM statut LEFT JOIN utilisateur ON utilisateur.statut = statut.id_statut


ça donne quoi ?


Message édité par Harkonnen le 12-06-2009 à 11:23:26

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 12-06-2009 à 11:22:36   

Reply

Marsh Posté le 12-06-2009 à 11:30:24    

Ah ça marche presque. En fait au lieu de m'afficher nom_util et prenom_util ça me met des NULL (alors que c'est rempli pourtant), en revanche l'intitule s'affiche bien.


Message édité par Profil supprimé le 12-06-2009 à 11:30:53
Reply

Marsh Posté le 12-06-2009 à 11:35:10    

Oui mais c'est normal que ça mette des NULL, le LEFT JOIN affiche toutes les données de la table de gauche (donc la table statut dans ton cas), même si elles ne sont pas remplies, alors que le INNER n'affiche que les données existantes. Je te l'ai fait faire pour justement vérifier si ta table comportait des données.

 

Donc si tu as des NULL, ça veut dire que ta table statut ne contient rien du tout par rapport à ton critère de jointure... Et c'est pour ça que ton INNER JOIN foire.


Message édité par Harkonnen le 12-06-2009 à 11:43:45

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 12-06-2009 à 15:57:28    

J'ai encore un peu de mal avec cette nouvelle syntaxe puisque au lycée on nous apprends a travailler uniquement avec le WHERE.
Et j'ai bien regardé le nom de mes champs et leu contenu et rien n'est vide, comment ça se fait  :??:

Message cité 1 fois
Message édité par Profil supprimé le 12-06-2009 à 16:04:04
Reply

Marsh Posté le 12-06-2009 à 16:13:43    


Et bien ton lycée à tout faux !
Le WHERE sert à filtrer une requête, pas à faire une jointure. Il faut savoir que cette syntaxe date de 1986, il serait temps d'évoluer.
L'avantage de la syntaxe avec INNER est multiple :
- ça permet de bien distinguer la partie de la requête qui concerne la jointure de la partie qui fait partie du filtre. Quand tu as une grosse requête sur plusieurs tables avec plein de clauses WHERE, ça devient vite chiant de décortiquer la requête pour trouver les WHERE qui concernent la jointure et les WHERE qui font partie du filtre. Avec JOIN, pas d'ambiguité possible
- imagine la requête suivante :

Code :
  1. SELECT a, b, c, d, e
  2. FROM toto, tata, tutu, titi
  3. WHERE toto.xxx = 3
  4. AND toto.yyy > 9
  5. AND titi.uuu != NULL
  6. AND tata.fff = 'kikoo lol asv ?'
  7. AND toto.id = tata.id
  8. AND tata.id = tutu.id
  9. AND titi.id = toto.id


Maintenant, tu te rends compte que ta requête ne donne pas les résultats escomptés. Tu choisis de débugger en virant une clause WHERE. Mais tu te plantes et tu vires la ligne "AND tata.id = tutu.id".
Résultat : plus de jointure entre tata et tutu. Tu lances ta requête, et comme il n'y a plus de jointure entre ces tables, tu te retrouves avec un produit cartésien entre tata et tutu, qui peut mettre ton serveur à genoux si ces tables contiennent plusieurs milliers d'enregistrements.
Le WHERE pour les jointures, c'est le mal. Les profs qui enseignent ça devraient bruler en enfer.

 

Quant à ton problème, difficile de t'aider sans la base sous les yeux.


Message édité par Harkonnen le 12-06-2009 à 16:14:18

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 12-06-2009 à 16:35:03    

Merci pour l'exemple, ça permet en effet de mieux se rendre compte, et je maintiens que notre prof de SQL ne nous a jamais mentionné l'existence de INNER et LEFT JOIN  :sweat:  
 
Sinon pour mon soucis tout est réglé  ;)  Il y avait une mauvaise incrémentation d'un champ ce qui faisait tout capoter  :)  
 
Encore merci pour le coup de main et la leçon sur le INNER  
 
 :hello:

Reply

Marsh Posté le 16-06-2009 à 10:54:41    

Un ptit up pour une nouvelle question  :)  
 
J'ai deux tables Materiel(id_materiel, etat_materiel) et une table Type(id_type, type_machine, marque, #num_mat)
 
J'aimerai afficher uniquement les machines qui sont de type 'ordinateur'. Donc je fais la requête suivante.
 
SELECT id_materiel,etat_materiel,marque,description_type  
FROM materiel  
LEFT JOIN type  
ON type.num_mat = materiel.id_materiel
AND type_machine = 'ordinateur'
ORDER BY id_materiel;
 
Le problème c'est que la requête m'affiche quand même l'id_materiel et etat_materiel des machines qui ne sont pas des ordinateurs.
 
J'ai du mal à voir comment je pourrais corriger ça  :sweat:  
 
Merci

Reply

Marsh Posté le 16-06-2009 à 11:01:05    

WHERE type_machine = 'ordinateur'  
 
car c'est un filtre ça, pas une jointure

Reply

Marsh Posté le 16-06-2009 à 11:04:39    

Ah oui exact. Merci beaucoup.
 
Ça va finir par rentrer un jour, si si  :o

Reply

Marsh Posté le 16-06-2009 à 11:05:36    

Voilà, c'est exactement ce que je disais... A force de faire des jointures avec des WHERE, on finit par ne plus distinguer ce qui est jointure et ce qui est filtre... Les profs qui enseignent de cette façon méritent la peine de mort :sarcastic:


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 16-06-2009 à 11:20:05    

Exactement, mauvaise habitude  :sweat:  Mais bon je vais corriger ça, merci à vous deux  :jap:

Reply

Marsh Posté le 17-06-2009 à 10:42:38    

Deamon a écrit :

WHERE type_machine = 'ordinateur'  
 
car c'est un filtre ça, pas une jointure


d'ailleurs, ça c'est un des points positifs d'ACCESS sur les autres SGBD : sur ce point il est bien plus rigoureux que les autres, puisqu'il plante si on met un filtre dans une clause "ON".
 
sympa pour prendre en main la syntaxe du coup

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed