我的数据如下:
id name score
--------------------
a apple 0.2
a apple 0.7
a apple 1.1
a banana 1.2
b cherry 0.8
b lemon 0.9
c mango 2.4
c raspberry 1.9
d strawberry 0.7
d lemon 1.1
对于每个id,我想选择得分最高的行,但只选择id和name:
id name
----------
a banana
b lemon
c mango
d lemon
以下查询使用sqlite完成工作。 (在this answer中对此进行了解释,为什么此查询在大多数DBMS中实际上无效):
SELECT id, name from (SELECT id, name, max(score) from data group by id);
问题是:如果没有子查询,这可能吗?
注意:我目前正在使用sqlite,但我正在寻找便携式解决方案。如果只有特定于供应商的解决方案,那么它也是一个有效的答案。 This question类似,但不讨论子查询的必要性。
答案 0 :(得分:2)
便携式解决方案意味着标准SQL。在标准SQL中,这通常使用窗口函数来解决。
select id, name
from (
select id, name, dense_rank() over (partition by id order by score desc) as rnk
from the_table
) t
where rnk = 1;
以上是标准SQL,基本上适用于所有现代DBMS(甚至是MariaDB和即将推出的MySQL 8.0)。但是,我不认为SQLite支持窗口功能。
您原始的子查询:
SELECT id, name, max(score)
from data
group by id
是无效的标准SQL,因为name
列既不是GROUP BY
的一部分,也不是在聚合函数中使用。基本上每个其他DBMS都会拒绝该查询 - 包括默认启用ONLY_FULL_GROUP_BY
的MySQL的新版本。显然,SQLite允许这种无效分组,从而产生非确定性(=随机)结果。
该规则的唯一例外是,所有非分组列的分组对分组列具有已知的功能依赖性。这意味着如果分组列是主键,并且所有非分组列都属于该主键的表。据我所知,只有Postgres目前支持这一点。