从表中为特定语言环境选择最合适的行

时间:2019-03-19 10:09:36

标签: mysql

我正在尝试设计一个[MySQL]查询,该查询将允许我从数据库中获取项目,并为用户的语言环境恢复最合适的项目,然后回退到系统/默认语言环境。

此查询的规则集是:

  1. 完全匹配
  2. 语言匹配,但地区不同
  3. 系统默认值

由于要在其中实施该系统,因此我具有以下要求:

  • 我无法明确指定要选择的列,因此COALESCE()可能不合适
  • 子查询还可以,性能很重要,但是我希望获得正确的内容
  • 我们可以假设系统/默认语言环境中的项目始终有一行

我尝试编写各种包含子查询的查询,但是我找不到逻辑。

我有下表:

CREATE TABLE `foo` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `foo_localised` (
  `id` int(11) unsigned NOT NULL,
  `language` varchar(5) NOT NULL,
  `region` varchar(5) NOT NULL,
  `label` varchar(150) DEFAULT NULL,
  PRIMARY KEY (`id`,`language`,`region`),
  CONSTRAINT `foo_localised_ibfk_1` FOREIGN KEY (`id`) REFERENCES `foo` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

其中包含以下行:

INSERT INTO `foo` (`id`)
VALUES (1),(2),(3);

INSERT INTO `foo_localised` (`id`, `language`, `region`, `label`)
VALUES
  (1, 'en', 'GB', 'I only wear trousers to a wedding'),
  (1, 'en', 'US', 'I only wear pants to a wedding'),
  (1, 'es', 'ES', 'Solo llevo pantalones para una boda'),
  (2, 'en', 'GB', 'Good day, sir'),
  (2, 'es', 'ES', 'Hola, amigo'),
  (3, 'en', 'GB', 'My name is Pablo'),
  (3, 'de', 'DE', 'Ich heiße Pablo');

以下语言环境的预期结果如下(默认为en_GB):

en_GB
1, I only wear trousers to a wedding
2, Good day, sir
3, My name is Pablo

en_US
1, I only wear pants to a wedding
2, Good day, sir
3, My name is Pablo

es_ES
1, Solo llevo pantalones para una boda
2, Hola, amigo
3, My name is Pablo

de_DE
1, I only wear trousers to a wedding
2, Good day, sir
3, Ich heiße Pablo

1 个答案:

答案 0 :(得分:0)

因此,我计算出以下查询,该查询可以实现我想要的目标。

它假定请求使用西班牙(西班牙)的项目,并且默认为英语(英国)。它将提供西班牙语(西班牙)结果,然后是西班牙语结果(例如西班牙语(墨西哥)),最后是英语(英国)。

SELECT 
    fl.*,
    (SELECT COUNT(*) FROM foo_localised fl1 WHERE fl1.id = fl.id AND fl1.language = 'es' AND fl1.region = 'ES') exists_exact,
    (SELECT COUNT(*) FROM foo_localised fl2 WHERE fl2.id = fl.id AND fl2.language = 'es' AND fl1.region != 'ES') exists_language

FROM foo f

LEFT JOIN foo_localised fl ON fl.id = f.id

HAVING

-- Return the row if the "group" has an exact match, and _this_ is the exact match
(exists_exact = 1 AND `language` = 'es' AND `region` = 'ES')

-- Return the row if the "group" has an alternative language variant
OR (exists_exact = 0 AND `language` = 'es')

-- Return the row if there is no exact or language row, and it is the default locale
OR (exists_exact = 0 AND exists_language = 0 AND `language` = 'en' AND `region` = 'GB')

此查询不需要我对表的结构有所了解(当然idlanguageregion除外)。

发布作为其他人的解决方案。它可以很好地满足我的要求,但是我不是100%确信这是一个有效的解决方案。欢迎发表评论和反馈。