2015-11-22 22 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