我正在处理sqlite3
上的yelp数据集,我有一个架构如下:
CREATE TABLE businesses
(business_id text primary key,
name text,
full_address text,
city text,
stars decimal(1,1),
ratings integer);
我运行以下查询:
select name, stars from businesses where ratings >= 400;
我得到以下内容:
Pho Kim Long |3.5
Pho So 1 |3.5
Ichiza |4
...
Guy Fieri |3.5
Giada |4
如果我跑:
select name, min(stars) from businesses where ratings >= 400;
我得到The Quad Las Vegas Resort & Casino|2
但如果我跑:
select name
from (select name, min(stars)
from businesses
where ratings >= 400);
我得到Giada
。
我知道有一种方法可以用LIMIT X
做到这一点,但为什么会出现这种情况呢?我忽略了SQLite解析器的某些内容吗?
答案 0 :(得分:2)
在SQLite docs中,它说:
如果SELECT语句是没有GROUP BY的聚合查询 子句,然后评估结果集中的每个聚合表达式 一次跨越整个数据集。每个非聚合表达式 对于任意选择的行,对结果集进行一次计算 数据集。每个使用相同的任意选择的行 非聚合表达。
换句话说,在这种情况下,您获得的实际名称纯粹是随机的,它与实际具有最小值stars
的行没有任何关系。
根据SQL-92标准,在包含聚合表达式和非聚合表达式的查询中,所有非聚合表达式都必须出现在GROUP BY子句中。 SQL-2003有一组类似但更复杂的规则。这个blog article提供了摘要。
某些数据库允许进行包含聚合和非聚合表达式的查询,而不包含任何GROUP BY子句,或者没有包含在GROUP BY子句中的所有非聚合,但是您发现结果可能是不确定的。其他数据库将显示错误并拒绝运行查询。
很难就如何纠正您的查询提出具体建议,因为您尚未说明您想要获得的输出。如果您试图找出哪一行的最小值为stars
,那么Juan的答案中的一个提案应该有效。
答案 1 :(得分:1)
问题是您的MIN()
函数为stars
带来了最小值,但不是该行的名称匹配。
您可以进行交叉加入
SELECT name
FROM businesses b,
( SELECT min(stars) as MinValue
FROM businesses
WHERE ratings >= 400) as M
WHERE b.stars = M.MinValue;
或内在选择
SELECT name
FROM businesses b
WHERE b.stars = ( SELECT min(stars) as MinValue
FROM businesses
WHERE ratings >= 400);
答案 2 :(得分:1)
SQLite 3.7.11或更高版本保证未聚合列的值来自与min()或max()匹配的行。
但是,除非您使用的是最新版本之一,否则查询计划程序将优化远离查询返回的min()/ max()值。
您必须列出最外层查询中的min(stars)
。