MySQL 枢轴 table 用于多语言词典

MySQL pivot table for Multilingual Dictionary

我的 table 结构如下所示:

如您所见,它是一个多语言词典,每种语言的所有值都存储在同一个 table 中,重复 'key' 值。

我想要的是 SQL 语句来获取具有唯一性 'key' 的所有行,包括每种语言的 'value' 列。

到目前为止,我尝试过的方法有效,但仅适用于两种语言,仅此而已:

select a.*, b.value
from `translator_messages` a 
JOIN `translator_messages` b
on a.key = b.key and
a.lang !=b.lang
group by a.key

结果:

注意:最好有一个通用的 SQL 解决方案,而不是依赖 MySQL 特定的功能。

如果你想要只出现一次的键,那么你可以使用not exists:

select tm.*
from translator_messages tm
where not exists (select 1
                  from translator_messages tm2
                  where tm2.key = tm.key and tm2.id <> tm.id
                 );

或者,如果您只是希望每个键的所有值都在一个列中:

select tm.key, group_concat(value separator '|') as values
from translator_messages tm;

这会将所有值放在一个列中。如果您愿意,您甚至可以指定语言:

select tm.key, group_concat(lang, ':', value separator '|') as values
from translator_messages tm;

不要使用 GROUP BY a.key,因为它只为每个键显示一行,而不是所有翻译。如果您想一起查看同一键的所有翻译,但在不同的行中,请使用 ORDER BY a.key.

您可能还想将 a.lang != b.lang 更改为 a.lang < b.lang。当前查询将显示同一对行两次,一次显示 a.lang = en-USb.lang = fa-IR,然后再次显示 a.lang = fa-IRb.lang = en-US。使用 < 而不是 ! 使其仅显示第一对。

您需要 dynamic pivot table 才能完成。

SET @sql := NULL;

SELECT
    GROUP_CONCAT(t.output) INTO @sql
FROM
    (
        SELECT
            CONCAT(
                'MAX(CASE WHEN lang=\'',
                lang,
                '\' THEN `value` END) AS ',
                CONCAT(REPLACE (lang, '-', '_'),'_value')
            ) output
        FROM
            translator_messages
        GROUP BY
            lang
    ) AS t;


SET @SQL := CONCAT(
    'SELECT `key`,category,' ,@SQL,
    ' FROM translator_messages GROUP BY `key`'
);

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

WORKING DEMO

示例输入:

| id |  lang | category |   key | value |
|----|-------|----------|-------|-------|
|  1 | en-US |      app |  book |    v1 |
|  2 | fa-IR |      app |  book |    v2 |
|  3 | de-GE |      app |  book |    v3 |
|  4 | en-US |      app | salad |    v4 |
|  5 | fa-IR |      app | salad |    v5 |
|  6 | de-GE |      app | salad |    v6 |

示例输出(由上述查询生成):

|   key | category | de_GE_value | en_US_value | fa_IR_value |
|-------|----------|-------------|-------------|-------------|
|  book |      app |          v3 |          v1 |          v2 |
| salad |      app |          v6 |          v4 |          v5 |

注意:

Beware of MySQL max size for a string variable and GROUP_CONCAT.

If GROUP_CONCAT max length is the limit (1024 by default) you should alter the temporary setting (session-scope) for length of it. It's done by:

SET SESSION group_concat_max_len = 10000

Set group_concat_max_len permanently (MySQL config)