2012-12-30 79 views
0

我創建了兩個視圖來幫助計算user_diary_number,然後選擇其中用戶的日記數>總用戶user_diary_number的平均值。mysql有...> avg()無法按預期方式工作

兩種觀點都象下面這樣:

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個用戶的日記號> average diary_num。事實上,我共有251個日誌和103個用戶。一些用戶有9,4,5個日記。 但結果只有在有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

你不能以這種方式使用avg。在我的個人電影數據庫,

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

生產什麼,

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

產生預期的結果。

1

您必須在單獨的子查詢中計算平均值。

喜歡的東西:

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

您可以用情理之中的事情填補空白

+0

謝謝:)我修好了。 –

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(count)。

別名爲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關鍵字是否包括或省略


一個問題:是否爲「視圖的SELECT語句包含在子查詢從MySQL支持子句「?

A: MySQL的真正舊版本(3.x?)不支持子查詢。但是當然,MySQL 5.1和更高版本確實支持子查詢。

要回答你的問題,是的,SELECT語句可以用作內聯視圖作爲另一個查詢的行源,例如,

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

我打算說,如果沒有羣組,平均值就不起作用,但正如你從我的例子中可以看出的那樣。在這種情況下,它在整個桌子上工作; 「select *,avg(year)from movie;」產生一行。 – prosfilaes

+0

thx爲您的具體筆記和答案。還有一個問題是,MySQL支持「View的SELECT包含FROM子句中的子查詢」?謝謝。 –

相關問題