mysql有...> avg()无法按预期工作

时间:2012-12-30 01:25:30

标签: mysql having average

我创建了两个视图来帮助计算user_diary_number,然后选择日记号为>的用户。总用户的user_diary_number的平均值。

两个观点如下:

create view user_diary_number as
(
select user_id,count( distinct diary_id ) as diary_num
from user_diary

group by user_id
);

,第二次使用havingavg

create view hw_diary as
(
select u.user_id, u.realname, ud.diary_num, school.school_name
from (user as u cross join user_diary_number as ud on u.user_id = ud.user_id )cross join school on u.school_id = school.school_id
having diary_num > avg(diary_num)

);

现在问题是,第二个视图只有1行结果。并且绝对地,我们有超过1个用户,其日记号>平均diary_num。实际上,我总共有251个日记和103个用户。一些用户有9,4,5日记。 但结果只有1个用户有3本日记。

我的相关表格是:

CREATE TABLE IF NOT EXISTS `school` (
  `school_id` int(11) NOT NULL,
  `school_name` varchar(45) NOT NULL,
  `location` varchar(45) NOT NULL,
  `master` varchar(45) NOT NULL,
  `numbers_of_student` int(11) NOT NULL,
  PRIMARY KEY (`school_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `user_diary` (
  `diary_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `title` varchar(45) NOT NULL,
  `content` varchar(255) NOT NULL,
  `addtime` DATETIME NOT NULL,
  PRIMARY KEY (`diary_id`,`user_id`),
  KEY `fk_diary_user_id_idx` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

交叉加入有问题吗?或者是其他东西? 非常感谢!

3 个答案:

答案 0 :(得分:3)

你不能这样使用avg。在我的个人电影数据库中,

select * from movie having year > avg(year);

什么都不产生,

select * from movie having year > (select avg (year) from movie);

产生预期结果。

答案 1 :(得分:1)

您必须在单独的子查询中计算平均值。

类似的东西:

select ...
from ...
group by ...
having diary_num > (
    select avg(diary_num)
    from ...) 

你可以填写有意义的空白

答案 2 :(得分:1)

这样的东西应该返回你正在寻找的结果集:

 SELECT u.user_id
      , u.realname
      , c.diary_num
      , s.school_name
   -- , a.diary_avg
   FROM ( SELECT d.user_id
               , COUNT(DISTINCT d.diary_id) AS diary_num
            FROM user_diary d
        ) c
   JOIN user u
     ON u.user_id = c.user_id
   JOIN school s
     ON s.school_id = u.school_id
   JOIN ( SELECT AVG(v.diary_num) AS diary_avg
            FROM ( SELECT t.user_id
                        , COUNT(DISTINCT t.diary_id) AS diary_num
                     FROM user_diary t
                 ) v
        ) a
     ON a.diary_avg < c.diary_num
  ORDER BY 1

作为c别名的内联视图为我们提供每个用户的diary_num(计数)。

作为a别名的内联视图获取所有用户的所有diary_num的平均值。这让我们得到了计数的“平均值”,这就是原始查询打算做的事情。

作为替代方案,我们可以将每个用户的“平均”日记数量作为...所有日记的总数除以所有用户的总数。为此,请使用以下内容替换为a别名的内联视图:

        ( SELECT COUNT(DISTINCT t.diary_id)
                 / NULLIF(COUNT(DISTINCT v.user_id),0) AS diary_avg
            FROM user v
            LEFT
            JOIN user_diary t
              ON t.user_id = v.user_id
        ) a

这会产生略微不同的结果,因为它是对总计数的计算,而不是计算的平均值。


注意

CROSS关键字对MySQL优化器没有影响。

我们通常会将CROSS关键字作为未来审核人员的文档。它表明我们有目的地省略了通常的ON子句。 (作为一个修订版,当我们看到一个没有ON条款的JOIN时,我们的思想会竞争“可能的非预期笛卡尔产品”......作者包含CROSS关键字提醒我们(评论者)忽略ON条款是有目的的。

但MySQL优化器并不关心是否包含CROSS关键字。


还有一个问题:MySQL是否支持“View的SELECT包含FROM子句中的子查询”?

答: MySQL的旧版本(3.x?)不支持子查询。但当然,MySQL 5.1及更高版本确实支持子查询。

要回答您的问题,是的,SELECT语句可以用作内联视图作为另一个查询的行源,例如

SELECT v.*
  FROM (
         SELECT 1 AS foo
       ) v