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-US
和 b.lang = fa-IR
,然后再次显示 a.lang = fa-IR
和 b.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;
示例输入:
| 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
我的 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-US
和 b.lang = fa-IR
,然后再次显示 a.lang = fa-IR
和 b.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;
示例输入:
| 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