requete Jointure

Eléphanteau du PHP | 13 Messages

10 mars 2008, 22:35

Bonjour,

Je galere un peu pour trouver la bonne requete, voici ce que je veux!
Imaginons 3 tables :

TABLE1

Champs1 - Champs2
ABC - AAA
CDE - BBB
DFE - CCC


TABLE2

Champs1 - Champs3
ZER - ZDE
ABC - EZZ
UIO - OPE

TABLE3

Champs1 - Champs4
ABC - ERT
AZE - ERR
ZER - ERT


Je voudrais obtenir ce resultat :

Champs1 - Champs2 - Champs3 - Champs4
ABC - AAA - EZZ - ERT
ZER - - ZDE - ERT
CDE - BBB - -
DFE - CCC - -
UIO - - OPE -
AZE - - - ERR


En fait, je voudrais joindre les 3 tables par le champs commun 'champs1'
Je veux commencer par afficher les resultats des champs1 que l'on retrouve sur le plus de tables. Ensuite, ceux qu'on retrouve dans une seul table !
Ensuite, je mettrais le WHERE que je désire !

Merci encore de votre aide.

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

10 mars 2008, 23:06

Salut,

Merci de LIRE ATTENTIVEMENT les règlements et les suivre.

Rappel pratique - n'oubliez pas de :
  1. suivre ces quelques conseils de débogage
  2. préciser quel SGBD vous utilisez ainsi que sa version
  3. utiliser les balises

    Code : Tout sélectionner

    [/i] et [i]
    [/i] pour afficher vos requêtes SQL
  4. poster le schéma des tables pertinentes à votre requête sous la forme d'une instruction "CREATE TABLE" (fonction "Exporter" de phpMyAdmin)
  5. si nécessaire, poster un échantillon des données sous la forme d'une instruction "INSERT INTO"
Attention, suivre ces consignes est obligatoire. Merci de les lire attentivement.
 

Eléphanteau du PHP | 13 Messages

10 mars 2008, 23:10

Autant pour moi :

Je complete ce message :

J'utilise une serveur mysql 5 et php 5

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

10 mars 2008, 23:15

pssit, eh, il manque les points 4 et 5 ;)

C'est juste pour pouvoir t'aider ;)
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Eléphanteau du PHP | 13 Messages

10 mars 2008, 23:27

Voici le code SQL de l'exmple :

Code : Tout sélectionner

-- phpMyAdmin SQL Dump -- version 2.11.5 -- http://www.phpmyadmin.net -- -- Serveur: localhost -- Généré le : Lun 10 Mars 2008 à 22:25 -- Version du serveur: 5.0.51 -- Version de PHP: 5.2.5 SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -- -- Base de données: `test` -- -- -------------------------------------------------------- -- -- Structure de la table `resultat` -- CREATE TABLE `resultat` ( `champs1` varchar(10) NOT NULL, `champs2` varchar(10) NOT NULL, `champs3` varchar(10) NOT NULL, `champs4` varchar(10) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Contenu de la table `resultat` -- INSERT INTO `resultat` (`champs1`, `champs2`, `champs3`, `champs4`) VALUES ('ABC', 'AAA', 'EZZ', 'ERT'), ('ZER', '', 'ZDE', 'ERT'), ('CDE', 'BBB', '', ''), ('DFE', 'CCC', '', ''), ('UIO', '', 'OPE', ''), ('AZE', '', '', 'ERR'); -- -------------------------------------------------------- -- -- Structure de la table `table1` -- CREATE TABLE `table1` ( `champs1` varchar(10) NOT NULL, `champs2` varchar(10) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Contenu de la table `table1` -- INSERT INTO `table1` (`champs1`, `champs2`) VALUES ('ABC', 'AAA'), ('CDE', 'BBB'), ('DFE', 'CCC'); -- -------------------------------------------------------- -- -- Structure de la table `table2` -- CREATE TABLE `table2` ( `champs1` varchar(10) NOT NULL, `champs3` varchar(10) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Contenu de la table `table2` -- INSERT INTO `table2` (`champs1`, `champs3`) VALUES ('ZER', 'ZDE'), ('ABC', 'EZZ'), ('UIO', 'OPE'); -- -------------------------------------------------------- -- -- Structure de la table `table3` -- CREATE TABLE `table3` ( `champs1` varchar(10) NOT NULL, `champs4` varchar(10) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Contenu de la table `table3` -- INSERT INTO `table3` (`champs1`, `champs4`) VALUES ('ABC', 'ERT'), ('AZE', 'ERR'), ('ZER', 'ERT');
Il y a les trois tables et le resultat que je veux ;)

Merci !

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

11 mars 2008, 00:51

Pour la jointure, c'est facile, des LEFT JOIN avec la colonne qui va bien feront l'affaire.

Code : Tout sélectionner

SELECT r.champs1, t1.champs2, t2.champs3, t3.champs4 FROM resultat r LEFT JOIN table1 t1 USING (champs1) LEFT JOIN table2 t2 USING (champs1) LEFT JOIN table3 t3 USING (champs1)
En revanche, je ne comprends pas ce que tu veux dire par
Je veux commencer par afficher les resultats des champs1 que l'on retrouve sur le plus de tables. Ensuite, ceux qu'on retrouve dans une seul table
Pourrais-tu expliquer stp ?

Eléphanteau du PHP | 13 Messages

11 mars 2008, 07:52

Salut,

Merci pour ta réponse, mais en faite, ce que je veux c'est de faire un select dans la table1 table2 table3 pour obtenir la table resultat. La table resultat, n'existe pas dans ma base, c'est seulement pour comprendre le resultat que je veux avoir à partir de table1 table2 table3.

D'aprés mes tests, une simple jointure ne suffit pour avoir un resultat aussi complet que celui que je veux.

Dans ma phrase : Je veux commencer par afficher les resultats des champs1 que l'on retrouve sur le plus de tables. Ensuite, ceux qu'on retrouve dans une seul table
Ce la veut dire que dans mon exemple, on retrouve ABC dans les 3 tables donc on le retrouve en premier dans le resultat, ZER, on le retrouve 2 fois, donc on le retrouve en second et ainsi de suite (si cette ordre est possible en mysql ca serai bien :) )

Merci beaucoup

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

11 mars 2008, 08:13

Dans ce cas, on reste sur le même principe mais on l'adapte. Au passage, je te recommande fortement d'utiliser les "vrais" schémas et tables de ta base plutôt qu'un exemple théorique, ça permet de cibler plus précisément les besoins.

Si tu n'as pas de table "resultat" il te faut une table "x" qui coordonnera en quelque sorte les autres. Cette table devrait avoir deux colonnes : champs1 (clé primaire) et nb, où "nb" représente le nombre de table où "champs1" est présent. À chaque nouvelle insertion/suppression dans une des autres tables, tu insères un nouvel enregistrement dans "x" ou mets à jour l'enregistrement correspondant. Tu peux le faire dans ton application ou, si tu es sûr d'utiliser MySQL 5, par des procédures stockées.

Dans ton application, tu sauras probablement à l'avance si un enregistrement existe, ce qui te permettra de choisir un INSERT ou UPDATE, mais si ce n'est pas le cas tu peux toujours faire un INSERT IGNORE avec "nb" à 0 suivi d'un UPDATE pour l'augmenter, ou faire les deux en même temps avec ON DUPLICATE KEY

Code : Tout sélectionner

INSERT INTO x VALUES ('ABC', 1) ON DUPLICATE KEY UPDATE nb = nb + 1
En procédures stockées, sauf erreur

Code : Tout sélectionner

DELIMITER // CREATE TRIGGER ai_table1 AFTER INSERT ON table1 FOR EACH ROW BEGIN INSERT INTO x VALUES (NEW.champs1, 1) ON DUPLICATE KEY UPDATE nb = nb + 1; END // CREATE TRIGGER ad_table1 AFTER DELETE ON table1 FOR EACH ROW BEGIN DECLARE $nb INT; SELECT nb INTO $nb FROM x WHERE champs1 = OLD.champs1; IF ($nb > 1) THEN UPDATE x SET nb = nb - 1 WHERE champs1 = OLD.champs1; ELSE DELETE FROM x WHERE champs1 = OLD.champs1; END IF; END // CREATE TRIGGER ai_table2 AFTER INSERT ON table2 FOR EACH ROW BEGIN INSERT INTO x VALUES (NEW.champs1, 1) ON DUPLICATE KEY UPDATE nb = nb + 1; END // CREATE TRIGGER ad_table2 AFTER DELETE ON table2 FOR EACH ROW BEGIN DECLARE $nb INT; SELECT nb INTO $nb FROM x WHERE champs1 = OLD.champs1; IF ($nb > 1) THEN UPDATE x SET nb = nb - 1 WHERE champs1 = OLD.champs1; ELSE DELETE FROM x WHERE champs1 = OLD.champs1; END IF; END // CREATE TRIGGER ai_table3 AFTER INSERT ON table3 FOR EACH ROW BEGIN INSERT INTO x VALUES (NEW.champs1, 1) ON DUPLICATE KEY UPDATE nb = nb + 1; END // CREATE TRIGGER ad_table3 AFTER DELETE ON table3 FOR EACH ROW BEGIN DECLARE $nb INT; SELECT nb INTO $nb FROM x WHERE champs1 = OLD.champs1; IF ($nb > 1) THEN UPDATE x SET nb = nb - 1 WHERE champs1 = OLD.champs1; ELSE DELETE FROM x WHERE champs1 = OLD.champs1; END IF; END // DELIMITER ;
Avec une colonne "nb", rien de plus facile que de faire un ORDER BY nb DESC. Tu pourrais le faire dynamiquement, avec une grosse requête avec des jointures et des UNION, mais ce serait inefficace et finalement plus compliqué.

Eléphanteau du PHP | 13 Messages

11 mars 2008, 08:26

Merci pour ta réponse,

Le vrai besoin est de faire un comparateur de produit de plusieurs fournisseurs (Table1 =fournisseur1, etc ...)
Chaque table ont une seul chose en commun c'est la référence (Champs1).
J'arrive a faire un inner join, mais il ne m'affiche que ceux qui ont une ref identique dans chaque table et pas ceux qu'on ne retrouve pas dans toute les tables.

Je pense qu'avec tout ca, ca me fait un sacré requete.

Est ce que tu peux me dire la requete pour faire toutes les jointures mais sans gerer l'ordre.
Je m'explique, je veux que mon moteur de recherche ne soit pas trop lente, car en fait, je gere des centaine de milliers d'articles.
Au debut je fesait ma jointure dans le code PHP, mais j'ai vite compris ma douleur, c'est pour cela que je me tourne sur ma requete SQL.
Je voudrais n'en lancer qu'une (grosse) requete.

Merci