在SELECT中简化多个CASE调用

问题描述:

我有一个table_a,它有两个外键给表options的主键。在SELECT中简化多个CASE调用

I SELECT基于@_aValue等于中那些options主键中的任一个。如果我在那里停下来,我会得到一张表格,其中每行有两组选项。我只对主键等于@_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中工作。

+0

除了巧合之外,您不能以“它们在数据库中的顺序”检索行。您也不能让数据库管理系统将它们保存在一个订单中。当然,您可以编写查询,以便数据库管理系统轻松使用排序索引或存储引擎的功能(如果它选择的话)。 – philipxy 2014-11-22 05:38:38

+0

@philipxy:谢谢你澄清! – DudeOnRock 2014-11-22 05:44:02

+0

与拉动连接的行/索引相比,CASE比较没有任何成本。建议你测量。还比较建议的解决方案。 (总是测量以证明和检查优化。)对于人类和DBMS来说,这是非常简单的。也索引适当。也请尝试https://dba.stackexchange.com。 – philipxy 2014-11-22 06:23:02

我不认为你可以摆脱条件逻辑。但是,我认为你可以简化查询一下。第一个想法是使用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,如果两个表具有完全相同的格式,则可以使用*

+0

真棒,很多要学习!我会试验你的两个建议。 – DudeOnRock 2014-11-22 02:12:51