繁体   English   中英

MySQL-为B列的前N个条目选择A列的平均值

[英]MySQL - select average of column A for first N entries from column B

我有一个评分表,每个用户每天可以在其中添加一个评分。 但是每个用户可能会错过两次评级之间的几天。

我想获得每个user_idcreated_at的前7个条目的平均rating

我的桌子:

mysql> desc entries;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| rating     | tinyint(4)       | NO   |     | NULL    |                |
| user_id    | int(10) unsigned | NO   | MUL | NULL    |                |
| created_at | timestamp        | YES  |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+

理想情况下,我会得到以下信息:

+------------+------------------+
| day        | average_rating   |
+------------+------------------+
| 1          | 2.53             |
+------------+------------------+
| 2          | 4.30             |
+------------+------------------+
| 3          | 3.67             |
+------------+------------------+
| 4          | 5.50             |
+------------+------------------+
| 5          | 7.23             |
+------------+------------------+
| 6          | 6.98             |
+------------+------------------+
| 7          | 7.22             |
+------------+------------------+

我能得到的最接近的是:

SELECT rating, user_id, created_at FROM entries ORDER BY user_id asc, created at desc

根本不是很接近...

可能吗? 演出会很糟糕吗? 每次加载网页时都需要运行该程序,所以每天运行一次并保存结果会更好吗? (到另一张桌子!?)

编辑-第二次尝试

在寻求解决方案的过程中,我认为这将获得每个用户第一天的评分:

select rating from entries where user_id in
    (select user_id from entries order by created_at limit 1);

但是我得到:

ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'

所以现在我将与JOIN一起玩,看看是否有帮助。

编辑-第三次尝试,越来越近

我发现了这个stackoverflow帖子 ,它离我想要的更近了。

select e1.* from entries e1 left join entries e2 
on (e1.user_id = e2.user_id and e1.created_at > e2.created_at) 
where e2.id is null;

它获取每个用户第一天的评分。

下一步是弄清楚如何获得2到7天。我不能1.created_at > e2.created_at使用1.created_at > e2.created_at ,所以现在我真的很困惑。

编辑-第四次尝试

好的,我认为这是不可能的。 一旦确定了如何关闭“完全分组方式”,我意识到我可能需要使用limit <user_id>, <day_num>的子查询,为此,我得到了:

ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'

我当前的方法是只获取整个表,并使用PHP计算每天的平均值。

如果我理解正确,那么您希望获得用户给出的最后7个评分,并按给出评分的日期排序。 一个用户的最后7个评分可能与另一个用户的日期不同,但是无论日期如何,都将对它们进行平均。

首先,我们需要按用户和日期对数据进行排序,并为每个用户分配自己的递增行数。 为此,我添加了两个变量,一个用于最后一个用户ID,一个用于行号:

select e.created_at, 
  e.rating, 
  if(@lastUser=user_id,@row := @row+1, @row:=1) as row, 
  @lastUser:= e.user_id as user_id 
from entries e, 
  ( select @row := 0, @lastUser := 0 ) vars 
order by e.user_id asc, 
  e.created_at desc;

如果先前的user_id不同,则将行计数器重置为1。结果是:

+---------------------+--------+------+---------+
| created_at          | rating | row  | user_id |
+---------------------+--------+------+---------+
| 2017-01-10 00:00:00 |      1 |    1 |       1 |
| 2017-01-09 00:00:00 |      1 |    2 |       1 |
| 2017-01-08 00:00:00 |      1 |    3 |       1 |
| 2017-01-07 00:00:00 |      1 |    4 |       1 |
| 2017-01-06 00:00:00 |      1 |    5 |       1 |
| 2017-01-05 00:00:00 |      1 |    6 |       1 |
| 2017-01-04 00:00:00 |      1 |    7 |       1 |
| 2017-01-03 00:00:00 |      1 |    8 |       1 |
| 2017-01-02 00:00:00 |      1 |    9 |       1 |
| 2017-01-01 00:00:00 |      1 |   10 |       1 |
| 2017-01-13 00:00:00 |      1 |    1 |       2 |
| 2017-01-11 00:00:00 |      1 |    2 |       2 |
| 2017-01-09 00:00:00 |      1 |    3 |       2 |
| 2017-01-07 00:00:00 |      1 |    4 |       2 |
| 2017-01-05 00:00:00 |      1 |    5 |       2 |
| 2017-01-03 00:00:00 |      1 |    6 |       2 |
| 2017-01-01 00:00:00 |      1 |    7 |       2 |
| 2017-01-13 00:00:00 |      1 |    1 |       3 |
| 2017-01-01 00:00:00 |      1 |    2 |       3 |
| 2017-01-03 00:00:00 |      1 |    1 |       4 |
| 2017-01-01 00:00:00 |      1 |    2 |       4 |
| 2017-01-02 00:00:00 |      1 |    1 |       5 |
+---------------------+--------+------+---------+

现在,我们将其简单地包装在另一条语句中,以选择行号小于或等于7的平均值。

select e1.row day, avg(e1.rating) avg
from (
  select e.created_at,
    e.rating,
    if(@lastUser=user_id,@row := @row+1, @row:=1) as row,
    @lastUser:= e.user_id as user_id
  from entries e,
    ( select @row    := 0, @lastUser := 0 ) vars
  order by e.user_id asc,
    e.created_at desc) e1
where e1.row <=7 
group by e1.row;

输出:

+------+--------+
| day  | avg    |
+------+--------+
|    1 | 1.0000 |
|    2 | 1.0000 |
|    3 | 1.0000 |
|    4 | 1.0000 |
|    5 | 1.0000 |
|    6 | 1.0000 |
|    7 | 1.0000 |
+------+--------+

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM