简体   繁体   English

使用条件在 Mysql 中查找不同的行

[英]Find distinct rows in Mysql by using conditions

Vague title, sorry.标题模糊,抱歉。

I am trying to convert client code to "pure" sql in Mysql 5.7 (If it makes any difference - a solution can also apply only to MariaDB 10.1, too).我正在尝试将客户端代码转换为 Mysql 5.7 中的“纯”sql(如果有任何区别 - 解决方案也只能适用于 MariaDB 10)。

I have a "codes" table and "code_translations" table.我有一个“代码”表和“code_translations”表。 I am now trying to output the "best available translations" for each code in the code table.我现在正在尝试 output 代码表中每个代码的“最佳可用翻译”。

If there is request for give me the translations for Code "A" and translations language "de" - try to find a translation with "de" first.如果有要求给我代码“A”和翻译语言“de”的翻译 - 尝试首先找到带有“de”的翻译。 If not found - use an available translation for "en" (default fallback).如果未找到 - 使用“en”的可用翻译(默认后备)。 If there is not "en" - take the first translation available determined by the current ordering.如果没有“en” - 采用当前排序确定的第一个可用翻译。

From the fiddle:从小提琴:

CREATE TABLE codes (id SERIAL, code TEXT, country TEXT);
CREATE TABLE code_translations (id SERIAL, code_id INT, language TEXT, label TEXT);

INSERT INTO codes (id, code, country) 
VALUES 
    (1, 'A', 'DE'),  
    (2, 'B', 'DE'),
    (3, 'C', 'DE');

INSERT INTO code_translations (code_id, language, label) 
VALUES
    (1, 'de', 'A-de'),
    (1, 'en', 'A-en'),
    (1, 'fr', 'A-fr'),
    (2, 'de', 'B-de'),
    (2, 'en', 'B-en'),
    (3, 'nl', 'C-nl'),
    (3, 'ru', 'C-ru');

Basic Select - Yields just all rows:基本 Select - 只产生所有行:

SELECT c.code,ct.label
FROM codes c
JOIN code_translations ct ON c.id=ct.code_id
-- WHERE ct.language=de
-- WHERE ct.language=fr
-- WHERE ct.language=ru

Desired output:所需的 output:

-- WHERE language = de
-- output should be
-- |A|A-de| -- de is the direct match
-- |B|B-de| -- de is the direct match
-- |C|C-nl| -- first match determined by ordering

-- WHERE language = fr
-- output should be
-- |A|A-fr| -- fr is the direct match
-- |B|B-en| -- no "fr" - take "en"
-- |C|C-nl| -- first match determined by ordering

-- WHERE language = ru
-- output should be
-- |A|A-en| -- no "ru" - take "en"
-- |B|B-en| -- no "ru" - take "en"
-- |C|C-ru| -- ru is the direct match

You can use a correlated subquery to get the language for each code.您可以使用相关子查询来获取每个代码的语言。 You can get the desired language first, then English.您可以先获得所需的语言,然后是英语。 However, if those are not available there is no "first" language -- because SQL tables represent unordered sets.但是,如果这些不可用,则没有“第一”语言——因为 SQL 表代表无序集。 You can get an arbitrary language using:您可以使用以下方法获得任意语言:

select c.*, ct.language, ct.label
from (select c.*,
             (select ct.language
              from code_translations ct
              where ct.code_id = c.id
              order by ct.language = 'de' desc,
                       ct.language = 'en' desc
              limit 1
             ) as language
      from codes c
     ) c left join
     code_translations ct
     on ct.code_id = c.id and ct.language = c.language;

If you have an ordering to define the "first" language, you can include that as a third key in the order by .如果您有一个定义“第一”语言的顺序,您可以将其作为第三个键包含在order by中。

Here is a db<>fiddle. 是一个 db<>fiddle。

Use a correlated subquery that sorts the rows of code_translations for each code in such a way that the top row is either the queried language (if it exists), or the default fallback language (if it exists), or some other language.使用相关子查询对每个codecode_translations行进行排序,使得第一行是查询的语言(如果存在)、默认的后备语言(如果存在)或其他语言。
This sorting can be done with the function FIELD() .这种排序可以使用 function FIELD()来完成。
Finally use LIMIT 1 to get only the top row:最后使用LIMIT 1只获取第一行:

SELECT c.code,
       (
         SELECT ct.label
         FROM code_translations ct
         WHERE ct.code_id = c.id
         ORDER BY FIELD(ct.language, ?2, ?1) DESC
         LIMIT 1
       ) label
FROM codes c

Replace ?1 with the queried language and ?2 with the fallback language.?1替换为查询的语言,将?2替换为备用语言。

See the demo .请参阅演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM