从一个表中获取项目列表并从另一个表中添加聚合评级

时间:2010-10-13 22:21:20

标签: sql mysql

我目前有两个表,一个包含文档,另一个包含评级

doc_id | doc_groupid | doc_name | doc_time

然后

rating_id | rating_docid | rating_score

其中rating_score为-1或1。

我需要做的是使用单个查询来检索文档表WHERE groupid =#中的每一列,但也包含聚合评级的列。我可以使用

检索评级列表
  SELECT rating_docid,
         SUM(CASE WHEN rating_type = 1 THEN 1 ELSE 0 END ) AS UpVotes,
         SUM(CASE WHEN rating_type = -1 THEN 1 ELSE 0 END) AS DownVotes
GROUP BY rating_docid

这给了我一份文件清单(只要他们被评级)以及他们有多少赞成或弃牌。我显然可以很容易地用

获取文档列表
SELECT * FROM documents WHERE doc_groupid = #

但我不知道如何在没有子查询(使用JOIN或LEFT JOIN)的情况下执行此操作,我的理解太慢了。老实说,我不知道如何用子查询来做这个

所以我的问题是:

  1. 如何快速加入?
  2. 如何使用子查询执行此操作?
  3. 谢谢!

3 个答案:

答案 0 :(得分:0)

我想你需要像

这样的东西
SELECT * 
FROM documents d
LEFT JOIN 
(
   SELECT rating_docid,
     SUM(CASE WHEN rating_type = 1 THEN 1 ELSE 0 END ) AS UpVotes,
     SUM(CASE WHEN rating_type = -1 THEN 1 ELSE 0 END) AS DownVotes
     FROM rating_table
     GROUP BY rating_docid
)r ON (r.rating_docid = d.doc_id)
WHERE d.doc_groupid = ....

此外,如果将其更改为

,它可能会更快
 SELECT * 
FROM documents d
LEFT JOIN 
(
   SELECT rating_docid,
     SUM(CASE WHEN rating_type = 1 THEN 1 ELSE 0 END ) AS UpVotes,
     SUM(CASE WHEN rating_type = -1 THEN 1 ELSE 0 END) AS DownVotes
     FROM rating_table
     INNER JOIN documents d1 ON (d1.doc_id = rating_docid )
     WHERE d1.doc_groupid =...
     GROUP BY rating_docid
)r ON (r.rating_docid = d.doc_id)
WHERE d.doc_groupid = ....

答案 1 :(得分:0)

由于这两个连接可能看起来很奇怪但是,假设你的列可能已编入索引,应该表现得非常好。

SELECT d.doc_id, d.doc_name, d.doc_time
       SUM(rd.rating_type) * -1 as DownVotes,
       SUM(ru.rating_type) as UpVotes
FROM documents d
    LEFT JOIN ratings rd ON d.doc_id = rd.rating_docid AND rd.rating_type < 0
    LEFT JOIN ratings ru ON d.doc_id = ru.rating_docid AND rd.rating_type > 0
GROUP BY d.doc_id

您可能希望添加COALESCE http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_coalesce以防止查询在没有要加入的情况下返回NULL。

SELECT d.doc_id, 
       COALESCE(SUM(rd.rating_type), 0) * -1 as DownVotes,
       COALESCE(SUM(ru.rating_type), 0) as UpVotes
FROM documents d ...

如果要检查的文档很多,我不建议使用子查询,因为每个文档执行另一个查询都意味着需要大量的开销。

答案 2 :(得分:0)

使用:

   SELECT d.doc_id,
          d.doc_name,
          d.doc_time, 
          COALESCE(SUM(CASE WHEN r.rating_type = 1 THEN 1 ELSE 0 END), 0) AS upvotes,
          COALESCE(SUM(CASE WHEN r.rating_type = -1 THEN 1 ELSE 0 END), 0) AS downvotes
     FROM DOCUMENTS d
LEFT JOIN RATINGS r ON r.rating_docid = d.doc_id
    WHERE d.doc_groupid = ?
 GROUP BY d.doc_id, d.doc_name, d.doc_time

doc_time对我来说很奇怪,让我觉得你可以有重复但有不同的时间价值......

JOIN vs Subquery

JOIN(INNER和OUTER)不是子查询。为了使事情变得更复杂,子查询可能意味着:

  • SELECT子句中的查询(AKA子选择):

    SELECT (SELECT col FROM TABLE) AS col2, ...
    
  • WHERE或HAVING子句中的查询:

    WHERE col = (SELECT column FROM TABLE)
    HAVING col IN (SELECT cols FROM TABLE)
    
  • JOIN中的查询(AKA派生表,内联视图):

    LEFT JOIN (SELECT u.user,
                      COUNT(*) AS num
                 FROM TABLE u
             GROUP BY u.user) x ON x.user = t.column
    

关于一个人比另一个人好,没有严格的规则,因为这一切都取决于:

  • 表格结构
  • 数据
  • 索引和表统计信息
  • 预期成果

所有真正重要的是工作是在必要时通过一张桌子进行的 - 最好是一个。