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

Mysql 如果存在,请从表中选择,否则请从完全不同的表中选择,mysql,select,query-optimization,multiple-tables,multiple-select,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 MySq

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

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();
 }
我需要的是根据一个条件获取
价格
重量
,但是如果它不在表中,那么我需要从一个全新的表中获取另外两个字段
零售价格
,以及一个常数0(不管它是什么),而不受上一个表的约束我能在一个查询中得到这两个吗?


注意:请给我一个优化的查询,它不会强制多次读取相同的值(这个函数在一个操作中执行数千次,所以速度非常关键——这就是我试图在一个查询中获得它的原因)。谢谢。

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

(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)
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
这将返回0到2行。如果返回两行,则选择第一行

EDIT您可以尝试通过使用这个可怕的构造来避免第二次查询的开销。我不确定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
由于“limit”子句保证每个查询最多有一行,因此可以使用左连接,并使用“IF()”处理“map”记录的存在:


上面的查询假设map表中的price和weight不能为null。

如果没有结果,则返回map 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

我无意中得到了一个相当粗糙的解决方案。以下是一个人如何做到这一点:

(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)
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就不会将其视为普通的UNIONALL。阅读更多相关信息和

显然,您可以这样做以使其更有意义,但我认为它的性能不会更好:

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
子句将结果限制在第一个集。

我手头没有mysql实例来测试它-如果它不工作,请告诉我,我会删除答案,让你的问题看起来又是全新的。这是一种变通方法。我看到的这个查询的问题是,第二个select语句是不惜一切代价执行的,如果我们已经用第一个select得到了答案,那么这将变得多余。我在问题中指出,优化是强大的important@nawfal这当然是真的,尽管如果我正确理解
PK_ID
是主键,那么第二个查询比第一个查询便宜得多,而且
LIMIT 1
甚至没有发挥作用。除非您的第一个查询大部分时间都返回答案,否则这应该可以轻而易举地避免额外的数据库往返。。我的第一个选择,是,主要是提供输出。但是谢谢你的不同approach@nawfal我添加了第二次尝试。如果它有效,请不要告诉任何人我写了那个丑陋的怪物:)这与@dasblinkenlight的帖子的要点相同,因为它总是查询两个表。但是,这一个只保证一条记录。除了上面提到的一条外,上述查询的问题是,它将
m.price
g.weight
作为一个集合检索,或者根据不需要的空值将
m.weight
g.price
作为一个集合检索。我想要的是
m.price
m.weight
如果根据条件存在,如果不存在,那么我想要g.price和g.weight。希望它是清楚的。此外,与像
ifempty
这样的东西相比,IFNULL做了完全不同的事情。这不会产生正确的结果。如果
width=@width和height=@height
条件未全部满足,则返回一个空结果集,而不是globe中的值。此外,它可以将
m.price
g.weight
作为一个集合检索,或者根据不需要的空值将
m.weight
g.price
作为一个集合检索。我想要的是
m.price
m.weight
如果根据条件存在,如果不存在,那么我想要
g.price
g.weight
。希望它是清楚的。另外,
IFNULL
执行完全不同的操作,不检查其是否为空