如果存在则从表中选择,否则从完全不同的表中选择

时间:2012-04-17 14:17:05

标签: mysql select query-optimization multiple-tables multiple-select

我有一个查询来获取两个值:

string query = @"SELECT price, weight
                 FROM   map 
                 WHERE  width = @width AND height = @height LIMIT 1";

if (_connSource.State != ConnectionState.Open)
    _connSource.Open();
MySqlCommand cmd = new MySqlCommand(query, _connSource);
cmd.Parameters.AddWithValue("width", width);
cmd.Parameters.AddWithValue("height", height);
r = cmd.ExecuteReader();

if (!r.Read())
{
    r.Close();

    query = @"SELECT retail_price, 0
              FROM   globe
              WHERE  PK_Id = @PK_Id LIMIT 1"

    cmd = new MySqlCommand(query, _connSource);
    cmd.Parameters.AddWithValue("PK_Id ", 1);
    r = cmd.ExecuteReader();
 }

我需要根据条件获取priceweight,但如果表中没有,那么我需要另外两个字段retail_price,从一个没有前一个表约束的全新表中得到一个常量0(无关紧要)。 我可以在一个查询中获取这两个吗?

注意:请给我优化的查询,这些查询不会强制多次读取相同的值(此功能在一次操作中执行数千次,因此速度非常关键 - 我之所以想要得到的原因它在一个查询中)。感谢..

4 个答案:

答案 0 :(得分:3)

语法有点难看,但我认为你可以做到:

(SELECT price, weight
 FROM map 
 WHERE width = @width AND height = @height LIMIT 1)
UNION ALL
(SELECT retail_price as price, 0 as weight
 FROM  globe
 WHERE PK_Id = @PK_Id LIMIT 1)

返回0到2行。如果返回2行,则选择第1行。

编辑您可以尝试使用此怪异构造来避免第二次查询的成本。我不确定MySQL是否会很好地处理它,但它有可能避免第二个查询:

select
    ifnull(price, (select retail_price from globe where PK_Id = @PK_Id LIMIT 1))
,   ifnull(weight, 0)
from map 
WHERE width = @width AND height = @height LIMIT 1

答案 1 :(得分:1)

如果没有Resrytrow到地图WHERE那么 DBNull将被全局值替换

SELECT 
    price = IFNULL(map.price,gl.price), 
    weight = IFNULL(map.weight,0)
FROM   map 
LEFT JOIN globe gl ON PK_Id = @PK_Id    
WHERE  width = @width AND height = @height 
LIMIT 1

答案 2 :(得分:0)

由于您的“limit”子句保证每个查询最多有一行,您可以使用左连接,并使用“IF()”处理“map”记录的存在:

select ifnull(m.price,g.price), ifnull(m.weight,g.weight) from
(SELECT retail_price as price, 0 as weight
 FROM  globe
 WHERE PK_Id = @PK_Id LIMIT 1) g
LEFT JOIN
(SELECT price, weight
 FROM   map 
 WHERE  width = @width AND height = @height LIMIT 1) m
ON 1=1

上述查询假设地图表中的价格和权重不能为空。

答案 3 :(得分:0)

我偶然得到了一个非常hacky的解决方案。这是人们可以做到的:

SELECT price, weight
FROM map
WHERE width = @width AND height = @height LIMIT 1

UNION ALL

SELECT retail_price, 0
FROM  globe
WHERE PK_Id = @PK_Id LIMIT 1

如果我在第一次选择中得到答案,LIMIT 1子句实际上限制它读取第二个值。 请注意,我没有在任何地方添加括号,因此MySQL不会将其视为正常的UNION ALL 。阅读更多相关信息herehere

显然你可以这样做,以使其更有意义,但我认为它没有更好的表现:

SELECT price, weight
FROM map
WHERE width = @width AND height = @height LIMIT 1

UNION ALL

(SELECT retail_price, 0
FROM  globe
WHERE PK_Id = @PK_Id LIMIT 1) LIMIT 1

这里因为我添加了括号,它的工作方式与普通的UNION ALL类似,即如果可能,我应该获取两个记录,但查询末尾的最后一个LIMIT 1子句将结果限制为第一个集合。