如何选择未从MySQL数据库转换的值?

时间:2019-12-23 22:46:36

标签: mysql

我对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

任何建议或最佳做法将不胜感激!

3 个答案:

答案 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表中获取tr_lang,tr_status,我该怎么做?

首先,对于尚未翻译的语言,从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

Demo on SQLFiddle

答案 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