2015-11-22 26 views
1

我已經搜索類似的網站和所有的答案是指一個單獨的評級表,而不是像這樣的實現。平均評級與評級存儲在2列

我已經轉換一個WordPress網站在PHP/MySQL的一個自建的網站,想象實際的崗位是一個審查和評論是與原來的崗位實際的評論。

我遇到的問題是我的職位表和評價領域的分級字段爲每個評論輸入。

我試圖使用別名AvgRating作爲一個,但它只返回評論評級(c.rating),如果該行被刪除它從posts表中帶回評級,有沒有加入方式別名作爲平均評分?顯然只有這部分是錯誤的,但不會拋出錯誤。

SELECT p.post_id 
    , p.title 
    , AVG(p.rating) AvgRating 
    , AVG(c.rating) AvgRating -- returns average from comments field, if line is removed will return posts rating value instead.. 
    FROM posts p 
    LEFT 
    JOIN comments c 
    ON p.post_id = c.post_id 
WHERE p.post_id = $post_id 
    AND c.post_id = $post_id 
    AND active = 1 
GROUP 
    BY p.post_id 
    , p.title; 

我在嘗試獲取模式聚合計數標記的平均值。有一種方法可以在一個查詢中實現此目的嗎?或者是我唯一的選擇使用2個查詢返回2個平均值,並使用PHP函數返回兩者之間的平均值?

這是一個測試數據庫:

CREATE TABLE `posts` (
`post_id` int(11) NOT NULL, 
`cat_id` int(11) NOT NULL, 
`rating` int(11) NOT NULL, 
`title` varchar(255) NOT NULL, 
`content` varchar(5000) NOT NULL, 
`date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
`author` varchar(255) NOT NULL, 
`active` int(11) DEFAULT '0', 
`slug` varchar(255) NOT NULL, 
`user_submitted` int(11) NOT NULL DEFAULT '1' 
) ENGINE=InnoDB AUTO_INCREMENT=2157 DEFAULT CHARSET=latin1; 

CREATE TABLE `comments` (
`cmt_id` int(11) NOT NULL, 
`post_id` int(11) NOT NULL, 
`rating` int(11) NOT NULL, 
`comment` varchar(5000) NOT NULL, 
`cmt_author` varchar(255) NOT NULL, 
`cmt_email` varchar(255) NOT NULL, 
`ip_address` varchar(100) NOT NULL, 
`cmt_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
`cmt_status` int(11) NOT NULL DEFAULT '0' 
) ENGINE=InnoDB AUTO_INCREMENT=397 DEFAULT CHARSET=latin1; 

INSERT INTO `posts` (`post_id`, `cat_id`, `rating`, `title`, `content`, `date_added`, `author`, `active`, `slug`, `user_submitted`) VALUES 
(2, 9, 5, 'site1.com', 'Original post review body', '2010-05-07 05:00:00', '', 1, 'site1-com', 1); 

INSERT INTO `comments` (`cmt_id`, `post_id`, `rating`, `comment`, `cmt_author`, `cmt_email`, `ip_address`, `cmt_date`, `cmt_status`) VALUES 
(1, 2, 5, 'it is a good site test review', 'Anonymous', '', '', '2010-01-06 21:51:00', 1), 
(2, 2, 3, 'it is an average site test review', 'Anonymous', '', '', '2010-01-06 20:51:00', 1), 
(3, 2, 1, 'it is an bad site test review', 'Anonymous', '', '', '2010-01-06 23:51:00', 1), 
(4, 2, 0, 'neutral test review', 'Anonymous', '', '', '2010-01-06 22:51:00', 1), 
(5, 2, 2, 'below average test review', 'Anonymous', '', '', '2010-01-06 22:51:00', 1); 

查詢運行:

SELECT p.post_id 
, p.title 
, AVG(p.rating) AvgRating 
, AVG(c.rating) AvgRating -- returns average from comments field, if line is removed will return posts rating value instead.. 
FROM posts p 
LEFT 
JOIN comments c 
ON p.post_id = c.post_id 
WHERE p.post_id = 2 
AND active = 1 
GROUP 
BY p.post_id 
, p.title; 

上測試數據庫恢復運行此在phpMyAdmin:AvgRating:當前選擇不包含唯一的列。電網編輯,複選框,編輯,拷貝和刪除功能不可用

(這是可以預料的,因爲我錯誤地認爲這將令兩者的平均值爲別名列avgRating的一個實例)

結果:

post_id title  AvgRating AvgRating 
    2  site1.com 5.0000  2.2000 

所以這是正確的在一定意義上,而是如何在原崗位等級的5.000到的評論的評價2.2000因素? (5 + 5 + 3 + 1 + 0 + 2)/6=2.66667,期望的結果應該是2.6667而不是2.2000。 2.2000是唯一的評論評分的平均值,並在原崗位等級的5.000

+0

我錯過了什麼?這似乎太明顯了。兩個別名都是一樣的。所以在PHP中,第一個別名被第二個別名覆蓋。 – Strawberry

+0

另外'AND c.post_id = $ post_id'是多餘的(事實上,這會產生反作用,因爲它會將LEFT [OUTER] JOIN渲染爲INNER JOIN)。 – Strawberry

+0

嗨,是的,對不起,我意識到發生了這種情況,我努力從兩個表中獲得平均值,平均值來自評論評級領域,這很好,但需要考慮來自帖子評級領域的原始評級,並以某種方式將其添加到整體平均值。 – Chris

回答

0

一種方法是不保理與UNION ...

SELECT post_id 
    , AVG(rating) avg_rating 
    FROM 
    (SELECT post_id 
      , rating FROM posts 
     UNION 
      ALL 
     SELECT post_id 
      , rating 
     FROM comments 
    ) x 
GROUP 
    BY post_id; 

http://sqlfiddle.com/#!9/ad65d/14

+0

嘿,我試圖解釋我能做的最好,真的很感謝幫助,這是複雜的,因爲我從來沒有嘗試過,我明確表示,平均返回不是因子分解在原來的帖子表中評分,並且只返回評論平均評分。我如何得到所需的結果是在評論評級字段下添加另一行到與帖子評級字段完全相同的值,然後運行查詢。 – Chris

+0

@Chris查看上面編輯 – Strawberry

+0

嘿謝謝!這是一個非常乾淨的方式!事實上,我創建的功能在我發佈時在現場沒有經過測試,雖然它按照預期在測試數據庫上工作,但當測試按上述方式進行時,它沒有考慮原始評分是否爲零等。但現在我已經考慮到所有這些條件,所以它很好用,但是當我有更多的時間時,我會修改它並使用你的方法,因爲它是一種更簡潔的方式。非常感謝您的幫助! – Chris

0

我想通了使用PHP & SQL的混合物:(我本來想找一個不太混亂的方式做到這一點的SQL雖然)

<?php 
include_once('includes/dbcon.php'); 

foreach($db->query("SELECT 
p.post_id, 
p.title, 
p.rating AS oreview, 
SUM(c.rating) AS creview 
FROM posts p 
LEFT JOIN comments c ON p.post_id = 2 where active=1 
GROUP BY 
p.post_id, 
p.title") as $ratr) { 
//get count 
$stmt = $db->query('SELECT * FROM posts INNER JOIN comments ON comments.post_id=posts.post_id where comments.post_id=2 AND active=1'); 
$row_count = $stmt->rowCount(); 
$numreviews = $row_count+1; 
//echo $ratr['creview'] ."<br>"; 
//echo $ratr['oreview'] ."<br>"; 
echo ($ratr['creview']+$ratr['oreview'])/$numreviews; 
} 
?> 

或作爲一個例子的功能:

function aggRating($db,$post_id){ 
    foreach($db->query("SELECT 
    p.post_id, 
    p.title, 
    p.rating AS oreview, 
    SUM(c.rating) AS creview 
    FROM posts p 
    LEFT JOIN comments c ON p.post_id = ".$post_id." where active=1 
    GROUP BY 
    p.post_id, 
    p.title") as $ratr) { 
//get review count 
    $stmt = $db->query("SELECT * FROM posts INNER JOIN comments ON comments.post_id=posts.post_id where comments.post_id=".$post_id." AND active=1"); 
    $row_count = $stmt->rowCount(); 
    $numreviews = $row_count+1; //add original post review to total 
echo round(($ratr['creview']+$ratr['oreview'])/$numreviews,2); 
     } 
    } 

//return result (2.67) 
echo aggRating($db,$post_id); 
?> 
+0

如果您解決自己的問題非常好,而且我們喜歡與人共享未來的讀者,但請僅使用答案部分而不是修改問題。 – Flexo