SELECT DISTINCT:有重音时控制优先级?

时间:2012-02-29 17:41:16

标签: mysql sql select internationalization distinct

示例:

> SELECT name, culture FROM city_i18n WHERE ID = 2745;
+-------+---------+
| name  | culture |
+-------+---------+
| Paris | en_GB   |
| París | es_ES   |
| Paris | pt_BR   |
| Paris | pt_PT   |
+-------+---------+
4 rows in set (0.00 sec)

> SELECT DISTINCT name FROM city_i18n WHERE ID = 2745 AND culture IN ('es_ES', 'en_GB');
+-------+
| name  |
+-------+
| Paris |
+-------+
1 row in set (0.00 sec)

> SELECT DISTINCT name FROM city_i18n WHERE ID = 2745 AND culture IN ('es_ES', 'pt_PT');
+-------+
| name  |
+-------+
| París |
+-------+
1 row in set (0.00 sec)

注意两个SELECT DISTINCT的不同输出:Paris,París(带重音)

现在,始终给予es_ES优先权的简单方法是什么(即始终获得带重音的París)?

由于存在一些问题,一些澄清:只有口音不同的城市名称(根据整理)应该只显示一次。在这种情况下,显示的名称应具有文化es_ES的重音符。

3 个答案:

答案 0 :(得分:3)

问题是您的数据库中使用的归类序列。根据您的RDBMS,有大量关于校准序列的信息。更改归类序列时需要非常小心,因为它会产生意想不到的后果。

归类序列用于测试列的相等性或不等式。根据使用的排序规则,以下语句可以全部评估为真或假:

'TexT' = 'text'
'TEXT' = 'text'
'áéíóú' = 'aeiou'

在您的情况下,您需要选择一个将重音字母和常规字母视为不同值的整理顺序。目前您的数据库正在确定它们是相同的。完成后,您可以根据自己喜欢的culture

开发逻辑,以选择合适的值。

只是添加它似乎您的数据库当前正在确定Paris = París并且我怀疑无法保证将选择哪个不同的值,类似于没有确定结果集的顺序这一事实除非使用ORDER BY子句。

我想了一会儿。我认为最好的办法是创建一个CultureRank

CREATE TABLE CultureRank
(
    Rank INTEGER,
    Culture VARCHAR(5)
);

INSERT INTO CultureRank VALUES (1, 'es_ES');
INSERT INTO CultureRank VALUES (2, 'en_GB');
INSERT INTO CultureRank VALUES (3, 'pt_BR');
INSERT INTO CultureRank VALUES (4, 'pt_PT');

SELECT
    Name
FROM
    City_i18n
    LEFT JOIN CultureRank ON City_i18n.Culture = CultureRank.Culture
WHERE
    ID = 2745
AND City_i18n.Culture IN ('es_ES', 'pt_PT') -- If Required
ORDER BY
    IF(ISNULL(CultureRank.Culture),1,0), 
    CultureRank.Rank
LIMIT 1;

如果city_i18n中的文化不在CultureRank中,则需要ORDER BY ISNULL。这里的IsNull函数将确保CultureRank表中的文化被赋予最高优先权,然后如果这些文化都没有与城市相关联,那么引擎将从city_i18n表中为该城市选择随机文化。如果您希望将不在CultureRank中的文化作为首要任务,那么请更换1& ISNULL函数中的0个参数。

编辑:

SELECT
    Name
FROM
    City_i18n
    LEFT JOIN CultureRank ON City_i18n.Culture = CultureRank.Culture
WHERE
    ID = 2745
AND City_i18n.Culture IN ('es_ES', 'pt_PT') -- If Required
AND NOT EXISTS (
    SELECT
        NULL
    FROM
        City_i18n Cities
        LEFT JOIN CultureRank CitiesRank ON Cities.Culture = CitiesRank.Culture
    WHERE
        City_i18n.Name = Cities.Name
    AND CultureRank.Rank < CitiesRank.Rank)

这应该从City_i18n表中获取给定ID的每个Name,除非根据您的归类序列,在CultureRank表中具有更高排名的另一个具有相同名称的记录。

答案 1 :(得分:0)

PHP / MySQL中的Unicode很痛苦。请使用以下两行代码:

setlocale(LC_ALL, 'en_US.utf8');
mysql_query("SET NAMES 'utf8'");

将它们洒在你的代码中,如圣水。

答案 2 :(得分:0)

看起来我找到了解决方案:

 SELECT name FROM city_i18n
 WHERE (name != (SELECT name FROM city_i18n WHERE ID = 2745 AND culture = 'es_ES') 
        OR culture = 'es_ES')
 AND ID = 2745 AND culture IN ('es_ES', 'en_GB');

如果有更好的解决方案,我很高兴听到它!