Page 1 sur 1

Besoin d'aide pour une requête de multilanguisme

Posté : 30 mai 2007, 15:39
par PoichOU
Bonjour à tous,

je fais quelques développement sur un site php où il y a un principe de multilanguisme. Je souhaite faire une requête qui pointe sur une table et qui pointe sur une autre table si il n'y a pas de résultat.

Voici un exemple, j'ai 3 tables :

Code : Tout sélectionner

----------------------- | ITEM | ----------------------- | id | id_description | ----------------------- | 1 | 1 | | 2 | 2 | ----------------------- ----------------------------------------- | DESCRIPTION_FR_FR | ----------------------------------------- | id | description | ----------------------------------------- | 1 | voici la description de l'item 1 | | 2 | voici la description de l'item 2 | ----------------------------------------- ----------------------------------------- | DESCRIPTION_EN_EN | ----------------------------------------- | id | description | ----------------------------------------- | 1 | this is the item 1 description | -----------------------------------------
DESCRIPTION_FR_FR est la table langue par défaut, cad que l'id référencé dans le champ id_description de la table ITEM existe forcément.
DESCRIPTION_EN_EN est une table langue cad qu'il y a l'équivalent de la DESCRIPTION_FR_FR traduit en anglais, sauf que certaines valeurs peuvent ne pas être dedans (comme dans l'exemple).


Mon but est d'afficher chaque item en anglais, mais s'il n'existe pas de traduction anglaise alors il faut afficher la traduction française (qui existe forcément). Et dans chaque résultat afficher son origine. Soit obtenir avec l'exemple précédent le résultat suivant :

Code : Tout sélectionner

-------------------------------------------------------- | id_item | description | origine | -------------------------------------------------------- | 1 | this is the item 1 description | en_en | | 2 | voici la description de l'item 2 | fr_fr | --------------------------------------------------------

Il existe déjà un système pour faire cela en effectuant plusieurs requêtes (cad faire une boucle sur chaque item, puis pour chaque element faire une requete sur la table en_en et si il n'y a pas de résultat faire une requete sur la table fr_fr).
Mais on m'a dit que c'était possible de faire cela en une seule requête. Est-ce exact ?


Quelqu'un saurait m'aider ? Merci de votre aide

PoichOU

ps : voici le dump de la base si ça peut être utile

Code : Tout sélectionner

CREATE TABLE `item` ( `id` int(11) NOT NULL auto_increment, `id_description` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; CREATE TABLE `description_fr_fr` ( `id` int(11) NOT NULL auto_increment, `description` longtext NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; CREATE TABLE `description_en_en` ( `id` int(11) NOT NULL auto_increment, `description` longtext NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; INSERT INTO `description_fr_fr` ( `id` , `description` ) VALUES (1 , 'voici la description de l''item 1'), (2 , 'voici la description de l''item 2'); INSERT INTO `description_en_en` ( `id` , `description` ) VALUES (1 , 'this is the item 1 description'); INSERT INTO `item` ( `id` , `id_description` ) VALUES (1 , 1), (2 , 2);

Posté : 30 mai 2007, 16:01
par Hubert Roksor
Il existe une fonction, COALESCE(), qui retourne la première valeur non-NULL. Combinée avec une jointure externe ça devrait te donner ce que tu cherches, à savoir quelque chose comme

Code : Tout sélectionner

SELECT i.id, COALESCE(en.description, fr.description) AS description FROM items AS i JOIN description_fr_fr AS fr ON fr.id = i.id_description LEFT JOIN description_en_en AS en ON en.id = i.id_description
Au passage, renomme tes colonnes "id" qui portent à confusion. Une colonne ne devrait pas porter un nom différent selon la table où elle se trouve. "item_id", "description_id" dans toutes les tables et alors tu pourras simplifier tes requêtes

Code : Tout sélectionner

SELECT i.item_id, COALESCE(en.description, fr.description) AS description FROM items AS i JOIN description_fr_fr AS fr USING (id_description) LEFT JOIN description_en_en AS en USING (id_description)

Posté : 30 mai 2007, 16:07
par PoichOU
alors là je te tire un grand coup de chapeau !! c'est exactement ce que je voulais.

Je ne connaissait pas COALESCE, bah ça me plait bien !


merci beaucoup :D

Posté : 30 mai 2007, 16:12
par Hubert Roksor
Mouaip, c'est plutôt pratique en effet. D'ailleurs, si tu n'étais pas certain d'avoir toutes les descriptions en français tu pourrais remplacer le premier JOIN par LEFT JOIN et rajouter une troisième valeur à COALESCE(), qui servirait alors de valeur par défaut.

Posté : 13 juil. 2007, 15:11
par PoichOU
bonjour

je resort mon propre topic car j'ai un nouveau problème. En fait j'ai un nouveau champ dans ma table ITEM : id_lib
Un item peut ne pas avoir de libelle (id_lib = null) et le libelle peut ne pas exister dans la table LIBELLE_EN_EN

Code : Tout sélectionner

----------------------------------------- | ITEM | ----------------------------------------- | id | id_description | id_lib | ----------------------------------------- | 1 | 1 | null | | 2 | 2 | 1 | ----------------------------------------- ----------------------------------------- | DESCRIPTION_FR_FR | ----------------------------------------- | id | description | ----------------------------------------- | 1 | voici la description de l'item 1 | | 2 | voici la description de l'item 2 | ----------------------------------------- ----------------------------------------- | DESCRIPTION_EN_EN | ----------------------------------------- | id | description | ----------------------------------------- | 1 | this is the item 1 description | ----------------------------------------- ----------------------------------------- | LIBELLE_FR_FR | ----------------------------------------- | id | libelle | ----------------------------------------- | 1 | voici le libelle de l'item 2 | ----------------------------------------- ----------------------------------------- | LIBELLE_EN_EN | ----------------------------------------- | id | libelle | -----------------------------------------
comment puis je faire pour afficher le libelle s'il existe et dans la langue anglaise (EN_EN)

genre obtenir

Code : Tout sélectionner

--------------------------------------------------------------------------------------- | id_item | description | origine | libelle | --------------------------------------------------------------------------------------- | 1 | this is the item 1 description | en_en | null | | 2 | voici la description de l'item 2 | fr_fr | voici le libelle de l'item 2 | ---------------------------------------------------------------------------------------
Merci vraiment d'avance
PoichOU

ps : voici le dump de la base si ça peut être utile

Code : Tout sélectionner

CREATE TABLE `item` ( `id` int(11) NOT NULL auto_increment, `id_description` int(11) NOT NULL, `id_lib` int(11) NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; CREATE TABLE `description_fr_fr` ( `id` int(11) NOT NULL auto_increment, `description` longtext NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; CREATE TABLE `description_en_en` ( `id` int(11) NOT NULL auto_increment, `description` longtext NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; CREATE TABLE `libelle_fr_fr` ( `id` int(11) NOT NULL auto_increment, `libelle` longtext NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; CREATE TABLE `libelle_en_en` ( `id` int(11) NOT NULL auto_increment, `libelle` longtext NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; INSERT INTO `description_fr_fr` ( `id` , `description` ) VALUES (1 , 'voici la description de l''item 1'), (2 , 'voici la description de l''item 2'); INSERT INTO `description_en_en` ( `id` , `description` ) VALUES (1 , 'this is the item 1 description'); INSERT INTO `libelle_fr_fr` ( `id` , `libelle` ) VALUES (1 , 'voici le libelle de l''item 2'); INSERT INTO `item` ( `id` , `id_description`, `id_lib` ) VALUES (1 , 1, null), (2 , 2, 1);


edit : mais quel boulet je fais ! la réponse était donnée avant que je pose la question

Code : Tout sélectionner

SELECT i.id, COALESCE(en.description, fr.description) AS description , COALESCE(lib_en.libelle, lib_fr.libelle) AS libelle FROM item AS i LEFT JOIN description_fr_fr AS fr ON fr.id = i.id_description LEFT JOIN description_en_en AS en ON en.id = i.id_description LEFT JOIN libelle_fr_fr AS lib_fr ON lib_fr.id = i.id_lib LEFT JOIN libelle_en_en AS lib_en ON lib_en.id = i.id_lib
[/color]