[英]MySQL - select average of column A for first N entries from column B
我有一个评分表,每个用户每天可以在其中添加一个评分。 但是每个用户可能会错过两次评级之间的几天。
我想获得每个user_id
的created_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.