【问题标题】:select * from table where column = something or, when unavailable, column = something elseselect * from table where column = something 或者,如果不可用,column = something else
【发布时间】:2011-11-20 08:36:22
【问题描述】:

我正在寻找比以下查询更有效和/或更易于阅读的内容。解释问题的最佳方式是提供样本。

假设 MySQL 中的以下表结构表示我正在创建的应用程序中各种字符串的本地化上下文。

create table LOCALIZATION_TABLE (
   SET_NAME    varchar(36) not null,
   LOCALE      varchar(8)  not null default '_',
   ENTRY_KEY   varhcar(36) not null,
   ENTRY_VALUE text            null
);

alter table LOCALIZATION_TABLE
  add constraint UQ_ENTRY
  unique (SET_NAME, LOCALE, ENTRY_KEY);

假设表格中输入了以下值:

insert into LOCALIZATION_TABLE (SET_NAME, LOCALE, ENTRY_KEY, ENTRY_VALUE)
values
  ('STD_TEXT', '_',  'HELLO', 'Hello!'),
  ('STD_TEXT', '_',  'GOODBYE', 'Goodbye.'),
  ('STD_TEXT', 'ge', 'GOODBYE', 'Lebewohl')
;

我想选择德语(“ge”)的所有可用条目,如果不可用,则默认使用英文文本(“_”)。我目前使用的查询如下:

select * from LOCALIZATION_TABLE where SET_NAME = 'STD_TEXT' and LOCALE = 'ge'
union
select * from LOCALIZATION_TABLE where SET_NAME = 'STD_TEXT' and LOCALE = '_'
  and ENTRY_KEY not in (
    select ENTRY_KEY from LOCALIZATION_TABLE where BUNDLE = 'STD_TEXT' and LOCALE = 'ge'
  )

真的不喜欢这个查询的外观,我确信必须有更简洁的东西可以代替。任何帮助或正确方向的线索将不胜感激。虽然这可行,但它似乎并不正确

【问题讨论】:

    标签: mysql join views union


    【解决方案1】:

    您可以提供自定义排序,然后取第一行,如下所示:

    select * from (
        select *
        from LOCALIZATION_TABLE
        where SET_NAME = 'STD_TEXT'
        order by field(LOCALE, 'ge', '_') -- this provides the custom ordering
    ) x
    group by ENTRY_KEY; -- this captures the first row for each ENTRY_KEY
    

    说明:

    内部选择的order by field(LOCALE, 'ge', '_') 按您定义的顺序为您获取行 - 在这种情况下,首先是德语(如果存在),然后是英语(您可以将更多语言添加到列表中)。

    这里的“技巧”是在 not 列出非组列时使用 mysql 的“非标准”GROUP BY 行为(大多数服务器将此视为语法错误) - 它只是返回为每个组找到第一行。外部选择使用group by没有聚合来获取每个命名组的第一行

    使用您的数据输出此查询:

    +----------+--------+-----------+-------------+
    | SET_NAME | LOCALE | ENTRY_KEY | ENTRY_VALUE |
    +----------+--------+-----------+-------------+
    | STD_TEXT | ge     | GOODBYE   | Lebewohl    |
    | STD_TEXT | _      | HELLO     | Hello!      |
    +----------+--------+-----------+-------------+
    

    【讨论】:

    • 这看起来比我想出的快速而肮脏的查询更具可读性。谢谢。
    【解决方案2】:

    我认为您的查询很好。但这里有另一种方法:

    SELECT
          en.SET_NAME 
        , COALESCE(ge.LOCALE, en.LOCALE) 
        , en.ENTRY_KEY 
        , COALESCE(ge.ENTRY_VALUE, en.ENTRY_VALUE)
    FROM 
        LOCALIZATION_TABLE AS en
      LEFT JOIN 
        LOCALIZATION_TABLE AS ge
          ON  ge.ENTRY_KEY = en.ENTRY_KEY
          AND ge.LOCALE = 'ge'
          AND ge.SET_NAME = 'STD_TEXT'
    WHERE
          en.LOCALE = '_' 
      AND en.SET_NAME = 'STD_TEXT'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 2015-10-08
      相关资源
      最近更新 更多