【问题标题】:Simplifying multiple CASE calls inside SELECT简化 SELECT 中的多个 CASE 调用
【发布时间】:2014-11-22 01:26:38
【问题描述】:

我有一个table_a,它有两个外键指向表options 的主键。

SELECT 基于@_aValue 等于table_a 中的options 主键中的任何一个。如果我停在那里,我会得到一个表,其中表 a 中的每一行都有两组选项。我只对主键等于@_aValue 的选项感兴趣,因此只有一组选项,但我事先不知道table_a 中的两个值中的哪一个。此外,我有兴趣按它们在数据库中的顺序检索所有行,在我看来,这会产生两个查询,其结果必须排序不理想。我已经实现了一个可行的解决方案,但我认为它的效率很低,因为它对每一行执行相同的CASE 比较多次:

SELECT
    (CASE a.a_id_1 WHEN @_aValue THEN options_a.value_1 ELSE options_b.value_1 END) AS value_1,
    (CASE a.a_id_1 WHEN @_aValue THEN options_a.value_2 ELSE options_b.value_2 END) AS value_2,
    (CASE a.a_id_1 WHEN @_aValue THEN options_a.value_3 ELSE options_b.value_3 END) AS value_3,
FROM table_a AS a
INNER JOIN options AS options_a
    ON a.a_id_1 = options_a.options_id
INNER JOIN connection_details AS details_b
    ON a.a_id_2 = options_b.options_id
WHERE a.a_id_1 = @_aValue
    OR a.a_id_2 = @_aValue;

在我当前的版本中实际上有更多 CASE 比较。有没有办法进行一次比较,并根据该选择来自options_a 的值或来自options_b 的值?理想情况下,该解决方案应符合标准,但如果这不可能,我需要它在当前版本的 MySQL 和 MariaDB 5.3 中工作。

【问题讨论】:

  • 您不能“按照它们在数据库中的顺序”检索行,除非是巧合。你也不能让 DBMS 让它们保持“有序”。当然,您可以编写查询以使 DBMS 可以轻松使用排序索引或存储引擎的功能(如果需要)。
  • @philipxy:感谢您的澄清!
  • 与拉取连接的行/索引相比,CASE 比较没有任何成本。建议你测量。还与建议的解决方案进行比较。 (始终衡量以证明和检查优化的合理性。)对于人类和 DBMS,您的都是直截了当的。也适当地索引。也可以试试dba.stackexchange.com
  • @philipxy:所有的好建议,谢谢!

标签: mysql sql case mariadb


【解决方案1】:

我认为您无法摆脱条件逻辑。但是,我认为您可以稍微简化查询。第一个想法是使用LEFT JOINCOALESCE()

SELECT COALESCE(options_a.value_1, options_b.value_1) AS value_1,
       COALESCE(options_a.value_2, options_b.value_2) AS value_2,
       COALESCE(options_a.value_3, options_b.value_3) AS value_3
FROM table_a a LEFT JOIN
     options options_a
     ON a.a_id_1 = options_a.options_id AND
        a.a_id_1 = @_aValue LEFT JOIN
     connection_details details_b
     ON a.a_id_2 = options_b.options_id AND
        a.a_id_1 <> @_aValue
WHERE @_aValue IN (a.a_id_1, a.a_id_2);

其实还有一个更简单的方法:

SELECT o.value_1, o.value_2, o.value_3 AS value_3
FROM table_a a JOIN
     ((SELECT 'a' as which, oa.options_id, oa.value_1, oa.value_2, oa.value_3
       FROM options_a oa
       WHERE options_id = @_aValue
      ) UNION ALL
      (SELECT 'b' as which, cd.options_id, cd.value_1, cd.value_2, cd.value_3
       FROM connection_details cd
       WHERE options_id <> @_aValue
      )
     ) o
     ON a.a_id_1 = @_aValue or a.a_aid_2 = o.options_id
 WHERE @_aValue IN (a.a_id_1, a.a_id_2);

(我认为on 的条件是正确的,尽管我有点担心WHERE。)

对于union all,如果两个表的格式完全相同,您可以使用*

【讨论】:

  • 太棒了,有很多东西要学!我会尝试你的两个建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
  • 2016-03-02
  • 1970-01-01
  • 2017-12-16
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多