【问题标题】:mysql translation tables with missing language fallback缺少语言后备的mysql翻译表
【发布时间】:2016-08-30 13:12:11
【问题描述】:

我有一个这样的数据库结构:

国家

CREATE TABLE IF NOT EXISTS `countries` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
  `is_active` tinyint(1) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_5D66EBAD77153098` (`code`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

国家语言

CREATE TABLE IF NOT EXISTS `country_languages` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `language_id` int(11) DEFAULT NULL,
  `country_id` int(11) DEFAULT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_1532561982F1BAF4` (`language_id`),
  KEY `IDX_15325619F92F3E70` (`country_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

语言

CREATE TABLE IF NOT EXISTS `languages` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `iso` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `active` tinyint(1) NOT NULL DEFAULT '1',
  `is_primary` tinyint(1) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_A0D153795E237E06` (`name`),
  UNIQUE KEY `UNIQ_A0D1537961587F41` (`iso`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

还有语言表的数据:

id    name        iso
----------------------
1     English     en
2     German      de
3     Italian     it

还有国家表:

id    code
----------------
1     ie

国家语言表

id    country_id    language_id    name
----------------------------------------------
1     1             1              Ireland in English
2     1             2              Ireland in German

我正在尝试编写一个查询,该查询将返回以下结果以便能够显示它。 (如果可能的话)

(Language)          (Country name)
English             Ireland in English
German              Ireland in German
Italian             #NULL OR EMPTY STRING

其次,我想了解是否可以将例如英语设置为默认语言,并且当不存在 id 为 3(意大利语)的语言内容时,默认应回退,结果如下所示:

(Language)          (Country name)
English             Ireland in English
German              Ireland in German
Italian             Ireland in English #please note language id is 3 -> Italian.

【问题讨论】:

  • 我对你的例子感到困惑。 “国家语言表”实际上是一个表还是查询的结果?还有紧随其后的查询,只是不清楚“id”应该是什么意思以及这些数据是如何组合在一起的......
  • @Jakumi 我已经更新了我的问题。我希望现在更清楚了

标签: php mysql database database-design


【解决方案1】:

好的,所以下面的查询可能不用子查询而是用连接来完成。我相信查询优化器会这样做,但我不太确定。

SELECT l.name as language,
       (SELECT cl.name 
        FROM country_languages cl 
        WHERE cl.country_id=[the wanted country id]
        ORDER BY cl.language_id=l.id DESC,
                 cl.language_id=1 DESC
        LIMIT 1) as country_name
FROM languages l

在此版本中,lan​​guage_id 1 用作首选后备,您可能可以以类似的方式添加更多语言。使用 FIND_IN_SET 作为二阶标准也可以(FIND_IN_SET(cl.language_id,'1,2,3') DESC 或您喜欢的任何顺序)。

当然,这个查询现在是针对固定的 country_id。它可以以类似的方式扩展到具有另一个连接的多个国家/地区:

SELECT l.name as language,
       (SELECT cl.name 
        FROM country_languages cl 
        WHERE cl.country_id=c.id 
        ORDER BY cl.language_id=l.id DESC,
                 cl.language_id=1 DESC
        LIMIT 1) as country_name
FROM countries c
JOIN languages l

子查询的替代方法是加入 country_languages 两次,然后只选择第一个不为空的(这可能是更清洁的解决方案之一):

SELECT l.name as language, 
       COALESCE(first.name, second.name) as country_name
FROM countries c
JOIN languages l
LEFT JOIN country_languages first ON 
        (first.country_id=c.id AND first.language_id=l.id)
LEFT JOIN country_languages second ON
        (second.country_id=c.id AND second.language_id=1)

如果语言 id 1 是您的后备语言。这也可以扩展以提供多种后备语言...

【讨论】:

  • 感谢您的评论。没有注意到默认值不应该适用于所有国家...
  • 一条评论。因为我使用SymfonyDoctrine 而不是IFNULL 应该使用COALESCE。对于IFNULL,人们应该写一个DoctrineExtension 类。
【解决方案2】:

这是使用连接的第一部分的查询:

SELECT `country_languages`.id, `country_languages`.country_id,`country_languages`.language_id, `country_languages`.name  FROM `countries` left join country_languages on `countries`.id=`country_languages`.`country_id`

您可以在国家/地区语言表中声明状态列并将状态设置为 0,1,2 以标记获取方式的优先级。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多