简体   繁体   中英

MySQL: Joining two tables and populating fields according to two columns in the joined table

I'm working on existing gallery system for which I want to make a few fields multilingual (title, source, description). A distinct table "translations" is used to store these translated texts. The "lang" column of this table stores the language code ("fr", "en", "de"). The "file_id" column stores to which file the translation relates.

I'm looking for the best way in MySQL to output the record for one file, with all its columns, including all translations as columns "title_fr, title_en, ..., description_de.

Tables structure:

    CREATE TABLE `files` (
      `id` int(10) unsigned NOT NULL auto_increment,
      `src` varchar(128) NOT NULL default '',
      `name` varchar(128) NOT NULL default '',
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

    CREATE TABLE `translations` (
      `id` int(10) unsigned NOT NULL,
      `file_id` int(10) unsigned NOT NULL,
      `lang` char(2) NOT NULL default '',
      `title` varchar(255) NOT NULL default '',
      `source` varchar(32) default '',
      `description` text,
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

I tried two ideas, but none worked.

1) The first idea was using VIEWs. Failed because of missing access rights on the shared hosting:

GRANT CREATE VIEW ON *.* TO 'the-user@the-host' IDENTIFIED BY PASSWORD  'here-the-password';

CREATE VIEW French AS
  SELECT f.id, title AS title_fr, source AS source_fr, description AS description_fr
  FROM files AS f LEFT OUTER JOIN translations AS t ON t.file_id = f.id WHERE (f.id=11 AND t.lang='fr');

CREATE VIEW English AS
  SELECT f.id, title AS title_en, source AS source_en, description AS description_en
  FROM files AS f LEFT OUTER JOIN translations AS t ON t.file_id = f.id WHERE (f.id=11 AND t.lang='en');

CREATE VIEW German AS
  SELECT f.id, title AS title_de, source AS source_de, description AS description_de
  FROM files AS f LEFT OUTER JOIN translations AS t ON t.file_id = f.id WHERE (f.id=11 AND t.lang='de');

SELECT * FROM  files AS f
  LEFT OUTER JOIN French ON f.id=French.id
  LEFT OUTER JOIN English ON f.id=English.id
  LEFT OUTER JOIN German ON f.id=German.id
  GROUP BY f.id;

2) The second idea is inspired from the example in this thread using a pivot table. In my case, I cannot use COUNT() and the following SQL query is not valid, but gives the idea. Sorry as there is some redundancy.

SELECT f.*,
  (CASE
    WHEN t.`lang`='fr'
    THEN t.title
    ELSE NULL
   ) AS title_fr,
  (CASE
    WHEN t.`lang`='en'
    THEN t.title
    ELSE NULL
   ) AS title_en,
  (CASE
    WHEN t.`lang`='de'
    THEN t.title
    ELSE NULL
   ) AS title_de,
  (CASE
    WHEN t.`lang`='fr'
    THEN t.source
    ELSE NULL
   ) AS source_fr,
  (CASE
    WHEN t.`lang`='en'
    THEN t.source
    ELSE NULL
   ) AS source_en,
  (CASE
    WHEN t.`lang`='de'
    THEN t.source
    ELSE NULL
   ) AS source_de 
  (CASE
    WHEN t.`lang`='fr'
    THEN t.description
    ELSE NULL
   ) AS description_fr,
  (CASE
    WHEN t.`lang`='en'
    THEN t.description
    ELSE NULL
   ) AS description_en,
  (CASE
    WHEN t.`lang`='de'
    THEN t.description
    ELSE NULL
   ) AS description_de
FROM files AS f WHERE id=11
LEFT OUTER JOIN
translations AS t
ON f.id=t.file_id
GROUP BY id

I also read about CONCAT and CONCAT_WS but they are not what I'm looking for, as I want to make further PHP processing as simple as possible.

Although you can't use count , you can use max , so try this query, it should be what you are looking for:

SELECT 
  f.id, f.src, f.name,
  MAX(CASE WHEN t.lang='fr' THEN t.title ELSE NULL END) AS title_fr,
  MAX(CASE WHEN t.lang='en' THEN t.title ELSE NULL END) AS title_en,
  MAX(CASE WHEN t.lang='de' THEN t.title ELSE NULL END) AS title_de,
  MAX(CASE WHEN t.lang='fr' THEN t.source ELSE NULL END) AS source_fr,
  MAX(CASE WHEN t.lang='en' THEN t.source ELSE NULL END) AS source_en,
  MAX(CASE WHEN t.lang='de' THEN t.source ELSE NULL END) AS source_de,
  MAX(CASE WHEN t.lang='fr' THEN t.description ELSE NULL END) AS description_fr,
  MAX(CASE WHEN t.lang='en' THEN t.description ELSE NULL END) AS description_en,
  MAX(CASE WHEN t.lang='de' THEN t.description ELSE NULL END) AS description_de
FROM files AS f 
LEFT OUTER JOIN translations AS t ON f.id=t.file_id
WHERE f.id=11
GROUP BY f.id, f.src, f.name;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM