0

我创建了两个视图来帮助计算 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
);

第二次使用havingand avg

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 个用户的日记数 > 平均日记数。事实上,我总共有 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 ;

交叉连接有问题吗?或者是其他东西?多谢!

4

3 回答 3

4

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

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

不产生任何东西,并且

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

产生预期的结果。

于 2012-12-30T01:33:19.710 回答
1

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

就像是:

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

你可以用有意义的东西填空

于 2012-12-30T01:37:59.810 回答
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

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

别名为 as 的内联视图为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 是否支持“视图的 SELECT 在 FROM 子句中包含子查询”?

答: MySQL 的真正旧版本(3.x?)不支持子查询。但可以肯定的是,MySQL 5.1 及更高版本确实支持子查询。

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

SELECT v.*
  FROM (
         SELECT 1 AS foo
       ) v
于 2012-12-30T01:51:12.623 回答