我对MySQL的了解是基础知识,这是我第一次遇到此问题。
我有3个表格,状态,语言和翻译。
语言表
+---------------+---------------+---------------+ | language_id | language_name | language_code | +---------------+---------------+---------------+ | 1 | English | en | | 2 | Español | es | | 3 | Italiano | it | +---------------+---------------+---------------+
状态表
+--------------+ | pt_status_id | +--------------+ | 1 | | 2 | +--------------+
翻译表
+-----------+---------+----------+---------+----+ | tr_status | tr_name | tr_lang | +-----------+---------+----------+---------+----+ | 1 | for rent | en | | 2 | for sale | en | | 1 | alquiler | es | +-----------+---------+---------+---------+-----+
我正在尝试获取未转换的值。在此示例中:
for sale
未翻译成西班牙语for rent
未翻译成意大利语for sale
未翻译成意大利语这是我的MySQL查询:
SELECT languages.*, tr_name, tr_lang FROM languages
LEFT JOIN tr_ptstatus ON tr_lang = language_code
WHERE tr_status IN (
SELECT tr_status
FROM tr_ptstatus
GROUP BY tr_status HAVING count(*) < (SELECT count(*) FROM languages)
)
我还在SQLFiddle中创建了一个链接:http://sqlfiddle.com/#!9/d3ad12/1
任何建议或最佳做法将不胜感激!
答案 0 :(得分:2)
@Barmar是正确的,解决此类问题的一种简单方法是首先计算所有可能组合的矩阵
SELECT DISTINCT pt_status_id, language_code
FROM tr_ptstatus
CROSS JOIN language
由于输出仅是Ids,我们必须决定以哪种语言显示结果,以使用户更轻松地处理信息,在以下结果集中,您将在第二列中看到基于完全定义的英语的观察,嵌套查找以获取状态码的英语翻译。
总是从源表中返回ID,在这种情况下为'pt_status_id',因此您可以提取尚未翻译成英语的状态代码。
现在您的最终SQL是:
SELECT t1.pt_status_id
,(SELECT tr_name FROM tr_ptstatus WHERE tr_lang = 'en' and tr_status = t1.pt_status_id) as 'English'
, language_code
FROM (
SELECT DISTINCT pt_status_id, language_code
FROM pt_status
CROSS JOIN languages
) AS t1
LEFT JOIN tr_ptstatus AS t2 ON t1.pt_status_id = t2.tr_status AND t1.language_code = t2.tr_lang
WHERE t2.tr_status IS NULL
结果:
pt_status_id English language_code
1 For Sale it
2 For Rent it
1 For Sale es
作为一般性的设计讨论,对于此类问题,我通常会选择“或默认”语言,并将默认定义放在tr_ptstatus
(状态定义)表中,这样对于此类问题,默认的可读值可用而无需太多子查询。
直接在状态表中具有默认字符串值或默认转换的另一个好处是,开发大量应用程序并在以后或与开发并行添加转换将变得非常容易。
以前我希望 ALL 值由另一个团队转换或管理时使用的约定(不要让开发人员编写最终用户会看到的内容)是包装所有默认值在[方括号]中,或全部设为大写。现实情况是总是需要显示默认值,在您的情况下,我们已经说过它是“英语”,但是关于您的数据模式的任何内容都不能向用户解释,我们必须观察所有值结论
尝试建立数据库模式来解释或记录您要写入数据的方式。如果不小心,仅出于规范化的考虑,规范化是非常隐秘的。
问:如何在此结果集中添加语言名称?
这是您发挥SQL能力的地方:),一种简单的方法是通过languages
重新加入language_code
表,您将可以访问其中的任何其他字段那个桌子。
我们之前使用子查询进行了演示,这次我们将添加一个联接:
LEFT JOIN languages ON t1.language_code = languages.language_code
但是我们还需要在SELECT
子句中添加一个新字段,否则您可以将先前对language_code
的引用替换为选择列。
SELECT t1.pt_status_id
,(SELECT tr_name FROM tr_ptstatus WHERE tr_lang = 'en' and tr_status = t1.pt_status_id) as 'English'
, languages.language_name
FROM (
SELECT DISTINCT pt_status_id, language_code
FROM pt_status
CROSS JOIN languages
) AS t1
LEFT JOIN tr_ptstatus AS t2 ON t1.pt_status_id = t2.tr_status AND t1.language_code = t2.tr_lang
LEFT JOIN languages ON t1.language_code = languages.language_code
WHERE t2.tr_status IS NULL
首先,对于尚未翻译的语言,从tr_ptstatus
表中返回这些字段是没有意义的,因为这些字段为空。
但是,如果您想从 English 翻译中看到这些其他字段,那么我们需要更改查询,以使 default 或 reference 语言(在这种情况下,在查询中使用JOIN
语言为 English ,这样我们就可以轻松访问任何其他字段。
通常,从
JOIN
表中选择字段比使用子查询更有效。但是,子查询的使用通常可以使代码更具可读性或可维护性,少数子查询的性能影响通常并不明显,但是如果您需要从子查询中检索多个列,则应该考虑改用JOIN
语法。
在下面的查询中,JOIN
替换了子查询,但是您会发现从每个查询中返回tr_status
并没有太多意义。表,因为此查询使用该公共字段值来链接所有表,如您在结果中所见,它们都是相同的,除了缺少的转换表中的值外,它们都是NULL
,因为没有从相应的行中选择一个值。
SELECT t1.pt_status_id
, ref.tr_name as 'Reference'
, languages.language_name
, t2.tr_lang, t2.tr_status
, ref.tr_lang as 'Ref Lang', ref.tr_status as 'Ref Status'
FROM (
SELECT DISTINCT pt_status_id, language_code
FROM pt_status
CROSS JOIN languages
) AS t1
LEFT JOIN tr_ptstatus AS t2 ON t1.pt_status_id = t2.tr_status AND t1.language_code = t2.tr_lang
LEFT JOIN languages ON t1.language_code = languages.language_code
LEFT JOIN tr_ptstatus AS ref ON ref.tr_lang = 'en' and ref.tr_status = t1.pt_status_id
WHERE t2.tr_status IS NULL;
pt_status_id Reference language_name tr_lang tr_status Ref Lang Ref Status
1 For Sale Español (null) (null) en 1
1 For Sale Italiano (null) (null) en 1
2 For Rent Español (null) (null) en 2
答案 1 :(得分:1)
此查询将为您提供尚未转换为所有其他语言的所有值:
SELECT t.tr_status,
MIN(CASE WHEN t.tr_lang = 'en' THEN t.tr_name END) AS tr_name,
GROUP_CONCAT(t.tr_lang) AS languages
FROM tr_ptstatus t
GROUP BY t.tr_status
HAVING COUNT(*) < (SELECT COUNT(*) FROM languages)
输出(用于示例数据)
tr_status tr_name languages
1 For Sale en
2 For Rent en,es
答案 2 :(得分:0)
编写一个子查询,该子查询生成状态和语言的所有组合的表。然后LEFT JOIN
和所有翻译一起找到丢失的组合。
SELECT t1.*
FROM (
SELECT DISTINCT pt_status_id, language_code
FROM tr_ptstatus
CROSS JOIN languages
) AS t1
LEFT JOIN translations AS t2 ON t1.pt_status_id = t2.tr_status AND t1.language_code = t2.tr_lang
WHERE t2.tr_status IS NULL