SQL - 从 avg 中选择 id

Posted

技术标签:

【中文标题】SQL - 从 avg 中选择 id【英文标题】:SQL - select the id from an avg 【发布时间】:2013-01-12 08:56:32 【问题描述】:

我的桌子是:

CREATE TABLE Rating
(
    rid INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    mid INTEGER FOREIGN KEY REFERENCES Movie(movieId) ON DELETE CASCADE, 
    uid INTEGER FOREIGN KEY REFERENCES User(id) ON DELETE CASCADE,
    rating INTEGER NOT NULL, 
);

我想选择评分最高的中档:

select avg(r.rating) from rating r

witch 返回平均值。我想返回平均评分最高的中档。任何想法如何做到这一点?

>更新

另外两个表:

CREATE TABLE User(
    id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    passwordhash VARCHAR(100) NOT NULL,
    fullname VARCHAR(50) NOT NULL,
    birthday DATE NOT NULL,
    joindate DATE NOT NULL,
    email VARCHAR(50) NOT NULL,
    picturepath VARCHAR(256) NOT NULL,
    favouritemovie VARCHAR(50) NOT NULL,
    favouritecategory INTEGER REFERENCES category(id),
    isDeleted BOOLEAN NOT NULL
);

CREATE TABLE Movie
(
    movieId INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    moviePath VARCHAR(500) NOT NULL
);

【问题讨论】:

你是什么意思“但是我没有得到中后卫?” ?在你的 Java 代码中获取它? 嗯。平均值是一个聚合函数。这是对一堆行进行操作的结果,因此涉及到一堆mids - 数据库应该如何知道你想要哪一个? 此外,返回的平均值可能不是您在rating 列中找到的值。 我认为,有几行具有相同的中间值。 OP 可能想要平均评分最大的中间值。 @maximus 叫我视觉,但一些示例数据和预期输出会有很大帮助:) 【参考方案1】:

来自您的 cmets:

计算每个中间值的平均评分(使用 GROUP BY 中间值),然后选择最大值并返回中间值

所以第一步,计算每个中间值的平均值:

select mid, 
       avg(rating) as avg_rating
from rating
group by mid;

现在选择最大值:

select max(avg_rating)
from (
  select avg(rating) as avg_rating
  from rating
  group by mid
) as mar

现在结合这些:

select ar.mid, mar.max_avg
from (
    select mid, 
           avg(rating) as avg_rating
    from rating
    group by mid
  ) as ar
  join (
    select max(avg_rating) as max_avg
    from (
      select avg(rating) as avg_rating
      from rating
      group by mid
    ) as t
  ) as mar
  on ar.avg_rating = mar.max_avg;

SQLFiddle 示例(使用 Postgres,但也适用于 HSQLDB):http://sqlfiddle.com/#!12/e208a/8

这不是最简单的解决方案,但查询分组数据从来都不是。使用 Luther 所示的 TOP 构造会快得多。 TOP 1 的唯一缺点是您不会注意到两部电影是否具有相同的平均评分。

编辑:只是为了在 HSQLDB 之外扩展一点。在支持窗口函数的数据库(PostgreSQL、Oracle 等)中,这类问题非常简单:

select *
from (
  select mid, 
         avg(rating) as avg_rating,
         dense_rank() over (order by avg(rating) desc) as rnk
  from rating
  group by mid
) t
where rnk = 1;

特别容易找到第二高、第三高等等(where rnk = 2where rnk = 3),使用这些嵌套查询非常复杂 - 但使用TOP/LIMIT 方法时更容易一些。

【讨论】:

嘿,非常感谢您的回答。但是,我在加入电影表时遇到了一个巨大的问题,因为我得到了平均评分,但不知道如何正确地将它与电影表加入。我真的很感激你的回答!!! @a_horse_with_no_name 我之前使用了 row_num 并且放弃了考虑排名的想法..不错的一个..【参考方案2】:

大概是这样的:

SELECT TOP 10
  mid,
  avg(cast(r.rating as float))
FROM Rating r
GROUP BY mid
ORDER BY avg(cast(r.rating as float)) DESC

您不需要将等级更改为浮点数,但我认为如果您的等级为 4 和 5,您可能希望平均值为 4.5,而不是四舍五入为整数。

【讨论】:

应该是TOP 1 而不是TOP 10。比我的解决方案短得多(适用于不支持 TOP 或类似结构的 DBMS)【参考方案3】:

你说你想从大多数平均评分中选择中频.. 请试试这个..

select max(x.avgr)
from (
  select r.mid, avg(r.rating) avgr
  from rating r
  group by r.mid
) as x;

或试试这个:适用于Sql Server。

select Top 1 r.mid, avg(r.rating) as avgr
from rating r
group by r.mid
order by avgr desc
;

那些Top 不起作用的dbms 你可以改用limit 1..

    select r.mid, avg(r.rating) as avgr
    from rating r
    group by r.mid
    order by avgr desc Limit 1
    ;

【讨论】:

@a_horse_with_no_name 谢谢 :) sql vs mysql ... ;) 我添加了 `limit ` 这似乎有效。不确定,因为没有任何预期的结果可以匹配……反对…… HSQL(使用的那个)确实支持TOP(还有一些也不支持LIMIT..)这种方法的问题是你不去看平均评分相同的电影。如果这是可以接受的,那么使用 top/limit 绝对是最快的解决方案。

以上是关于SQL - 从 avg 中选择 id的主要内容,如果未能解决你的问题,请参考以下文章

什么是 SQL 查询以 5 分钟间隔选择数据和数据条目的 AVG

SQL Server 使用窗口函数计算 AVG()

从 SQL 中选择 JSON 并按 ID 连接元素

SQL:从两个表中选择类似列并通过 Id 给出约束

从 SQL Server 中具有公共 ID 的多条记录中选择数据

SQL 服务器。从2个表中选择数据[重复]