Problème de jointure

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Problème de jointure

par Snipy » 06 sept. 2007, 17:25

sadeq, tout simplement merci
Je ne connaissais pas ce point.
Que de subtilité à apprendre encore :p

par sadeq » 06 sept. 2007, 15:00

Car tout simplement, les alias de table telque "fa", "t", "m" et "m2", ne sont pas pris en compte par un mysql_fetch_... seuls les noms des champs sont récupèrés. C'est pourquoi il faut renommer les champs identiques provenant de différentes tables en leur donnant des alias différents dans la requête SQL.

Exemple, dans ta requête:

Code : Tout sélectionner

SELECT fa.id, fa.title, fa.timestamp, fa.status, fa.user_id, fa.idtopic, fa.idmodo, m2.pseudo AS pseudo_modo, m.pseudo, t.topic_titre AS topic_titre FROM ...
On remarque que l'on a 2 champs ayant le même nom "pseudo", pourtant l'un désigne le membre et l'autre le modo. SQL exige alors de les préfixer par l'alias de leurs tables d'origine.
Ainsi, m.pseudo désigne le pseudo du membre et m2.pseudo celui du modo.
ça c'est une régle SQL. Mais ça ne permet pas malheureusement la distinction entre les 2 champs côté php. C'est pour celà qu'il faut ajouter des alias de champs pour différencier les champs dans le résultat. Ainsi, m.pseudo as pseudo_user et m2.pseudo as pseudo_modo permet de renommer les 2 champs dans le résultat (pour php par exemple)

Tu peux voir ça en mettant un
print_r($row);
dans la boucle mysql_fetch_...

Remarque: Attention, les alias de champs ne sont pas exigé par SQL en cas d'homonymes seule la distinction par le préfixe du parent est exigée comme j'ai dit. Mais si on n'utilise pas d'alias de champs dans le cas d'homonymes, le résultat reçu sous php ne contiendra q'un seul des champs
homonymes (le dernier rencontré dans le SELECT en principe) c'est pourquoi il est fortement recommandé de donner des alias (surnoms) aux champs homonymes.

par Snipy » 06 sept. 2007, 14:29

Waou :shock:

Magnifique traduction que tu as faites de ma table,

Le problème que j'avais était que $row['fa.idmodo'] ne renvoyait rien..
Mais j'ai remarqué que $row['idmodo'] renvoit la bonne donnée.

Merci de ton aide.

Si tu pouvais juste me dire pourquoi l'un marche et pas l'autre pour ma culture personnelle :D

par sadeq » 04 sept. 2007, 14:59

Bonjour,
Je te fais une lecture de ta table et de ta requête et toi tu me diras si ce que j'ai compris est bien ce que tu veux.

Lecture de la table selon moi:

Code : Tout sélectionner

CREATE TABLE `forum_alertes` ( `id` mediumint(11) NOT NULL auto_increment, `idtopic` int(11) NOT NULL default '0', `title` varchar(255) collate latin1_german2_ci NOT NULL default '', `contenu` text collate latin1_german2_ci NOT NULL, `user_id` int(11) NOT NULL default '0', `status` tinyint(2) NOT NULL default '0', `idmodo` int(11) NOT NULL default '0', `timestamp` int(11) NOT NULL default '0', PRIMARY KEY (`id`), KEY `idtopic` (`idtopic`,`user_id`,`idmodo`) ) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci AUTO_INCREMENT=6 ;
Cette table forum_alertes enregistre vraisemblablement des messages d'alertes identifiés par un id unique et incrémentiel dans le temps.
  • Toute alerte est définie par un titre (title), un message (contenu), un état (status) et une date (timestamp)
    Toute alerte concerne un et un seul sujet (idtopic)
    Toute alerte concerne aussi un et un seule utilisateur (user_id)
    Toute alerte est suivie par un et un seul modérateur (idmodo)
La table a un index unique (clé primaire) qui est id et un index de recherche formé de idtopic, user_id et idmodo.

Quant à la requête de sélection:
$result = mysql_query('SELECT fa.id, fa.title, fa.timestamp, fa.status, fa.user_id, fa.idtopic, fa.idmodo, m2.pseudo AS pseudo_modo, m.pseudo, t.topic_titre AS topic_titre 
      FROM  forum_alertes AS fa 
      LEFT JOIN forum_topic AS t ON t.topic_id = fa.idtopic 
      LEFT JOIN membres AS m ON m.id = fa.user_id 
      LEFT JOIN membres AS m2 ON m2.id = fa.idmodo 
      ORDER BY fa.status ASC, fa.timestamp DESC') or die (mysql_error());
Elle extrait les informations concernant l'alerte (fa) : id, title, timestamp, status, user_id, idtopic et idmodo
Elle effectue une liaison entre la table forum_alerte et plusieurs autres tables liées à elle par des clés étrangères. Où chaque clé étrangère relie une table spécifique:
  • idtopic relie la table forum_topic (t) pour accèder à topic_titre
    user_id relie la table membres (m) pour atteindre le pseudo de l'utilisateur
    idmodo relie aussi la table membres (m2) pour accèder au pseudo du modérateur
Les liaisons sont formulées comme des jointures externes à gauche (ouvertes vers la table forum_alerte) pour inclure les alertes qui n'ont pas forcement de sujet, d'utilisateur ou de modo connus.

Et finalement la sélection trouvé est classée par ordre croissant des états d'alertes et par ordre décroissant du temps (de la plus récentes à la plus ancienne par état)

Au vu de la syntaxe est du rendu de cette requête testée sous Mysql, elle est correcte et retourne exactement ce que mon analyse a formulé.

Les éléments du test sont les suivants:

Code : Tout sélectionner

-- phpMyAdmin SQL Dump -- version 2.10.1 -- http://www.phpmyadmin.net -- -- Serveur: localhost -- Généré le : Mar 04 Septembre 2007 à 14:52 -- Version du serveur: 5.0.41 -- Version de PHP: 5.2.3 SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -- -- Base de données: `test` -- -- -------------------------------------------------------- -- -- Structure de la table `forum_alertes` -- CREATE TABLE `forum_alertes` ( `id` mediumint(11) NOT NULL auto_increment, `idtopic` int(11) NOT NULL default '0', `title` varchar(255) collate latin1_german2_ci NOT NULL default '', `contenu` text collate latin1_german2_ci NOT NULL, `user_id` int(11) NOT NULL default '0', `status` tinyint(2) NOT NULL default '0', `idmodo` int(11) NOT NULL default '0', `timestamp` int(11) NOT NULL default '0', PRIMARY KEY (`id`), KEY `idtopic` (`idtopic`,`user_id`,`idmodo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci AUTO_INCREMENT=8 ; -- -- Contenu de la table `forum_alertes` -- INSERT INTO `forum_alertes` (`id`, `idtopic`, `title`, `contenu`, `user_id`, `status`, `idmodo`, `timestamp`) VALUES (6, 1, 'a1', 'a1', 0, 1, 0, 4), (7, 2, 'a2', 'a2', 1, 1, 1, 1); -- -------------------------------------------------------- -- -- Structure de la table `forum_topic` -- CREATE TABLE `forum_topic` ( `topic_id` mediumint(11) NOT NULL auto_increment, `topic_titre` varchar(255) collate latin1_german2_ci NOT NULL default '', PRIMARY KEY (`topic_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci AUTO_INCREMENT=2 ; -- -- Contenu de la table `forum_topic` -- INSERT INTO `forum_topic` (`topic_id`, `topic_titre`) VALUES (1, 't1'); -- -------------------------------------------------------- -- -- Structure de la table `membres` -- CREATE TABLE `membres` ( `id` mediumint(11) NOT NULL auto_increment, `pseudo` varchar(255) collate latin1_german2_ci NOT NULL default '', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci AUTO_INCREMENT=3 ; -- -- Contenu de la table `membres` -- INSERT INTO `membres` (`id`, `pseudo`) VALUES (1, 'u1'), (2, 'modo1'); -- -- Requête testée -- SELECT fa.id, fa.title, fa.timestamp, fa.status, fa.user_id, fa.idtopic, fa.idmodo, m2.pseudo AS pseudo_modo, m.pseudo, t.topic_titre AS topic_titre FROM forum_alertes AS fa LEFT JOIN forum_topic AS t ON t.topic_id = fa.idtopic LEFT JOIN membres AS m ON m.id = fa.user_id LEFT JOIN membres AS m2 ON m2.id = fa.idmodo ORDER BY fa.status ASC , fa.timestamp DESC
Résultat du test:

Code : Tout sélectionner

id title timestamp status user_id idtopic idmodo pseudo_modo pseudo topic_titre 6 a1 4 1 0 1 0 NULL NULL t1 7 a2 1 1 1 2 1 u1 u1 NULL
Remarque: C'est normal d'avoir des null, car le test illustre exprès les cas de jointures à gauche (LEFT JOIN)

Problème de jointure

par Snipy » 01 sept. 2007, 11:41

Bonjour à tous,

J'ai une de mes jointures qui me pose soucis,

Code : Tout sélectionner

$result = mysql_query('SELECT fa.id, fa.title, fa.timestamp, fa.status, fa.user_id, fa.idtopic, fa.idmodo, m2.pseudo AS pseudo_modo, m.pseudo, t.topic_titre AS topic_titre FROM forum_alertes AS fa LEFT JOIN forum_topic AS t ON t.topic_id = fa.idtopic LEFT JOIN membres AS m ON m.id = fa.user_id LEFT JOIN membres AS m2 ON m2.id = fa.idmodo ORDER BY fa.status ASC, fa.timestamp DESC') or die (mysql_error());
Aucune erreur n'est affiché.
Mais j'ai certains champs tel que fa.timestamp ou m.pseudo qui ne s'affiche pas :roll:

J'aimerais savoir avant tout si vous voyez quelque chose d'incohérent dans cette requete :?

Voici la table forum_alertes
CREATE TABLE `forum_alertes` (
  `id` mediumint(11) NOT NULL auto_increment,
  `idtopic` int(11) NOT NULL default '0',
  `title` varchar(255) collate latin1_german2_ci NOT NULL default '',
  `contenu` text collate latin1_german2_ci NOT NULL,
  `user_id` int(11) NOT NULL default '0',
  `status` tinyint(2) NOT NULL default '0',
  `idmodo` int(11) NOT NULL default '0',
  `timestamp` int(11) NOT NULL default '0',
  PRIMARY KEY  (`id`),
  KEY `idtopic` (`idtopic`,`user_id`,`idmodo`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci AUTO_INCREMENT=6 ;
[/quote]

Si vous avez besoin d'autres choses n'hésitez pas,

Et d'avance merci car je commence à m'arracher les cheveux dessus, et je suis sur que c'est une petite erreur d'inatention ou autre :oops: