1

考虑 Bars and Beers 数据库中的以下关系:

sells (bar, beer, price):表示每个酒吧销售的每种啤酒的价格(注意每个酒吧可以卖很多啤酒,很多酒吧可以卖同一种啤酒,价格可能不同)。

以下查询查找可在任何酒吧找到的最低价格啤酒的名称。

SELECT s.beer
FROM sells s
WHERE NOT EXISTS (SELECT si.beer
FROM sells si
WHERE si.price <= s.price) 

嗨,我正在慢慢学习 sql,我无法理解“si.price <= s.price”部分。由于嵌套选择基本上是比较相同的两个表,所以整个查询不会总是返回一个空表吗?

4

4 回答 4

3

该查询中有一个错误 - 它永远不会返回任何行,因为没有价格不等于自身。

要工作,它应该是:

...
WHERE si.price < s.price) 


假设进行了更改,其工作原理的解释是内部查询对表中的每一行执行一次并且取决于外部表(称为“共同相关子查询”)。因为在内部查询中使用了同一张表,所以您需要给外部表起别名(在本例中为“s”)。内部查询断言没有(其他)价格低于正在执行的行中的价格。

顺便说一句,内部查询的别名是不必要的 - 您可以删除“s1”,它仍然可以工作,因为内部查询是默认范围:

SELECT beer
FROM sells s
WHERE NOT EXISTS (
    SELECT *
    FROM sells  -- no alias needed
    WHERE price <= s.price)

此外,这是一个“坏”查询,因为相关子查询会导致执行“n”个查询(每行一个)。你最好使用min()聚合函数:

SELECT beer
FROM sells
WHERE price = (SELECT min(price) FROM sells)

除了这个查询更简单、更容易理解(两件好事)之外,它执行得更快,因为只执行了两个查询(一个子查询找到最低价格,一个子查询获取包含它的整行)。


最后,最后一个(尽管是次要的)错误是,如果有多个价格相同的低价啤酒,所有这些都将返回多行。要返回最低价格啤酒,您需要将行数限制为 1 并决定如何打破平局(可能是在名称上)。事实上,只返回一行可以实现更简单的查询:

select beer
FROM sells
ORDER BY price
LIMIT 1

如果您需要不断打破平局(即不以相同的最低价格返回随机的同价啤酒),也可以按名称订购:

select beer
FROM sells
ORDER BY price, beer
LIMIT 1
于 2013-02-05T19:48:30.127 回答
1
SELECT s.beer, s.price
FROM sells s
GROUP BY s.beer
HAVING s.price = MIN(s.price)

小提琴: http ://sqlfiddle.com/#!2/f292c/1

请注意,这不是标准的。Mysql 允许不按选定的列进行分组。

于 2013-02-05T19:48:49.737 回答
1

嵌套查询正在比较相同的两个表。但是,它实际上更像是从表中取出一行,将其与表中的所有其他行进行比较,然后移动到下一行。这是一个概念性的解释。实际的实现可能完全不同。

但是,所写的查询不会返回任何内容,因为<=. 这应该是<

但是,有一个更简单的方法来编写这个查询:

select *
from sells
order by price
limit 1

祝你学习 SQL 好运。

于 2013-02-05T19:48:52.673 回答
0

只需按升序排列价格,并将结果集限制为一项:

SELECT bar, beer, price FROM sells ORDER BY price ASC LIMIT 1
于 2013-02-05T19:53:46.160 回答