【问题标题】:mysql: group functions on subqueries with limitsmysql:对具有限制的子查询进行分组
【发布时间】:2013-08-19 20:37:16
【问题描述】:

我有一组用户执行他们得分的任务。我正在尝试创建一个报告,显示每个用户最近 50 个任务的平均值。

用户表:用户 ID、用户名、用户类型
任务表:taskid, score, tasktype, userid

如果我这样做:

SELECT u.userid, u.username, (SELECT AVG(score)
                            FROM task t
                            WHERE t.userid = u.userid AND t.tasktype = 'task1'
                            ORDER BY t.taskid DESC LIMIT 50) AS avgscore
FROM user u
WHERE u.usertype = 'utype';

这是行不通的,因为它在计算所有内容的平均值后会限制 50。

我需要的是这个:

SELECT u.userid, u.username, AVG(SELECT t.score
                            FROM task t
                            WHERE t.userid = u.userid AND t.tasktype = 'task1'
                            ORDER BY t.taskid DESC LIMIT 50) AS avgscore
FROM user u
WHERE u.usertype = 'utype';

但这不是有效的语法

我尝试过子子查询,但也不能这样,因为当我在子子查询中引用 u.userid 时,总是遇到限制、连接或未知字段的问题.

有没有办法做到这一点?

【问题讨论】:

  • 感谢您的编辑 - 我以为我是这样的,但是当我发布时它并没有这样显示 - 你打败了我自己修复它。

标签: mysql subquery


【解决方案1】:

在子查询中使用子查询:

SELECT u.userid, u.username,
       (SELECT AVG(score)
        FROM (select t.*
              from task t
              WHERE t.userid = u.userid AND t.tasktype = 'task1'
              ORDER BY t.taskid DESC
              LIMIT 50
             ) t
       ) AS avgscore
FROM user u
WHERE u.usertype = 'utype';

编辑:

我没有意识到 MySQL 不会识别 u.userid。它应该根据 ANSI 规则来确定表别名的范围。

您可以采取不同的方法,即找到第 50 个 taskid 值,然后获取高于该值的所有内容:

select ut.userid, ut.username, avg(t.score)
from (SELECT u.userid, u.username,
             (SELECT substring_index(substring_index(group_concat(taskid order by taskid desc
                                                                 ), ',', 50), ',', -1)
              from task t
              WHERE t.userid = u.userid AND t.tasktype = 'task1'
             ) + 0 as taskid50
      FROM user u
      WHERE u.usertype = 'utype'
     ) ut join
     task t
     on ut.userid = t.userid and
        ut.taskid50 >= t.taskid and t.tasktype = 'task1'
group by ut.userid, ut.username;

【讨论】:

  • 我也试过了,但是在'where子句'中得到“未知列'u.userid'”。我什至尝试在第二级添加第二个用户表以加入,但是限制出现问题 - 当我这样做时,我似乎只能在所有用户中获得 50 分。
  • 那仍然行不通 - 现在它占用了 MIN 的 LIMIT 50,而不是 50 的 MIN。这基本上是回到原始问题的一个循环,取最后 50 个平均值,而不是 50平均值。也许这在 mysql 中是不可能的,因为它无法识别子查询中的外部别名。
  • @Inukshuk 。 . .呃。如果它不适用于avg(),它也不适用于min()。我试图避免我刚刚输入的公式。但是有一种方法。如果taskid 是一个整数,那么你应该输入+ 1 将字符串转换回一个整数。
  • 我看了,我读了,我理解了,然后我想不通为什么它不起作用。然后我可以了。它需要是 t.taskid >= ut.taskid50 (这很容易);而且在那个连接中,“ut.userid = t.userid”也不见了。并且使用 CAST() 可能比 +1 更好。感谢您的帮助!
  • 我尝试再做 2 次必要的小修改以使其正常工作,但尚未完成,所以我将它们发布在这里。连接需要 t.taskid >= ut.taskid50,并且您需要在 select 和 group by 子句(ut.userid、ut.username)上至少为 userid 指定一个表。
【解决方案2】:

试试这个

   SELECT u.userid, u.username, AVG(t.score ) AS avgscore
   FROM user u
   INNER JOIN task t 
   ON t.userid = u.userid
   WHERE u.usertype = 'utype' AND t.tasktype = 'task1'
   GROUP BY u.userid
   ORDER BY t.taskid DESC LIMIT 50;

【讨论】:

  • 不,只返回一个用户 ID/用户名和一个平均分数。我需要一份所有用户的列表,每个用户都有自己的最后 50 分。
  • 这仍然返回每个用户的所有“task1”类型任务的平均分数。限制 50 应用于要显示的用户数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-25
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多