2014-10-28 43 views
1
SELECT *, null AS score, 
     '0' AS SortOrder 
    FROM products 
    WHERE datelive = -1 
    AND hidden = 0 
UNION 
SELECT e.*, (SUM(r.a)/(COUNT(*)*1.0)+ 
     SUM(r.b)/(COUNT(*)*1.0)+ 
     SUM(r.c)/(COUNT(*)*1.0)+ 
     SUM(r.d)/(COUNT(*)*1.0))/4 AS score, 
     '1' AS SortOrder 
    FROM products e 
    LEFT JOIN reviews r 
     ON r.productID = e.productID 
     WHERE e.hidden = 0 
     AND e.datelive != -1 
    GROUP BY e.productID 
    HAVING COUNT(*) >= 5 
UNION 
SELECT e.*, (SUM(r.a)/(COUNT(*)*1.0)+ 
     SUM(r.b)/(COUNT(*)*1.0)+ 
     SUM(r.c)/(COUNT(*)*1.0)+ 
     SUM(r.d)/(COUNT(*)*1.0))/4 AS score, 
     '2' AS SortOrder 
    FROM products e 
    LEFT JOIN reviews r 
     ON r.productID = e.productID 
     WHERE e.hidden = 0 
     AND e.datelive != -1 
    GROUP BY e.productID 
    HAVING COUNT(*) < 5 
    ORDER BY SortOrder ASC, score DESC 

这会创建一个用于在页面上显示产品的SQL对象。第一个请求获取类型datelive = -1,第二个类型datelive != -1r.count(*) >= 5,第三个类型datelive != -1r.count(*) < 5。 reviews表的结构类似于如下:根据条件加入表,依靠条件

reviewID | productID | a | b | c | d | approved 
------------------------------------------------- 
    1   1  5 4 5 5  1 
    2   5  3 2 5 5  0 
    3   2  5 5 4 3  1 
    ...   ...  ... ... ... ... ... 

我试图去解决它,从而r.count(*)只关心approved = 1类型的行,因为清点基于未经批准的评论数据并不理想。我怎样才能加入这些表格,使得总分和行数仅取决于approved = 1

我试着在AND r.approved = 1中加入WHERE条件的连接,它不会做我想要的。它确实对它进行了排序,但不再包含零评论的项目。

+1

如果向第三个查询的WHERE添加AND R.approved = 1,会发生什么?此外,WHERE不会影响连接条件之后发生的连接条件(尽管RDBMS可能根据它进行更智能的连接),并将连续记录集中的行过滤掉。 – ydaetskcoR 2014-10-28 23:08:04

+0

@ydaetskcoR,在第三个查询中为'WHERE'添加'AND r.approved = 1'将排除评论表中零行的所有产品。如果某个产品没有评论,那么当我喜欢它时,它不再显示。 – gator 2014-10-28 23:12:22

回答

2

你似乎是几乎没有。

在你的问题中,你谈到了将AND r.approved = 1添加到连接标准,但是通过它的声音,你实际上将它添加到WHERE子句中。

如果改为正确添加到像下面的连接标准,那么它应该很好地工作:

SELECT *, null AS score, 
     '0' AS SortOrder 
    FROM products 
    WHERE datelive = -1 
    AND hidden = 0 
UNION 
SELECT e.*, (SUM(r.a)/(COUNT(*)*1.0)+ 
     SUM(r.b)/(COUNT(*)*1.0)+ 
     SUM(r.c)/(COUNT(*)*1.0)+ 
     SUM(r.d)/(COUNT(*)*1.0))/4 AS score, 
     '1' AS SortOrder 
    FROM products e 
    LEFT JOIN reviews r ON r.productID = e.productID 
    WHERE e.hidden = 0 
    AND e.datelive != -1 
    GROUP BY e.productID 
    HAVING COUNT(*) >= 5 
UNION 
SELECT e.*, (SUM(r.a)/(COUNT(*)*1.0)+ 
     SUM(r.b)/(COUNT(*)*1.0)+ 
     SUM(r.c)/(COUNT(*)*1.0)+ 
     SUM(r.d)/(COUNT(*)*1.0))/4 AS score, 
     '2' AS SortOrder 
    FROM products e 
    LEFT JOIN reviews r ON r.productID = e.productID AND r.approved = 1 
    WHERE e.hidden = 0 
    AND e.datelive != -1 
    GROUP BY e.productID 
    HAVING COUNT(*) < 5 
    ORDER BY SortOrder ASC, score DESC 

SQL Fiddle here

再次注意我如何简单地将AND r.approved = 1直接放在LEFT JOIN reviews r ON r.productID = e.productID之后,它为连接添加了额外的条件。

正如我在我的评论中提到的那样,WHERE子句将在联接完成后将行从联合记录集中过滤掉。在某些情况下,RDBMS可能会优化它并将其放入连接标准中,但只有在对结果集没有影响的情况下才可以。

+0

干杯,这工作很好。多么简单的错过;我不知道为什么它不再显示空分的项目,但这种方式确保它仍然可以。简单而快捷,谢谢! – gator 2014-10-28 23:27:06

-1

您可以创建一个只包含approved = 1的行的临时表,然后加入临时表而不是reviews

create table tt_reviews like reviews; 
insert into tt_reviews 
select * from reviews 
where approved = 1; 
alter table tt_reviews add index(productID); 

然后在你上面的查询替换reviewstt_reviews

1

计算非零和并将其加入到结果中可能会解决它;

fiddle

SELECT a.productID, 
     NULL AS score, 
     '0' AS SortOrder 
FROM products a 
WHERE datelive = -1 
    AND hidden = 0 
UNION 
SELECT e.productID, 
     (min(x.a)/(min(x.cnt)*1.0)+ min(x.b)/(min(x.cnt)*1.0)+ min(x.c)/(min(x.cnt)*1.0)+ min(x.d)/(min(x.cnt)*1.0))/4 AS score, 
     '1' AS SortOrder 
FROM products e 
JOIN reviews r ON r.productID = e.productID 
LEFT JOIN 
    (SELECT ee.productID, 
      sum(rr.a) AS a, 
      sum(rr.b) AS b, 
      sum(rr.c) AS c, 
      sum(rr.d) AS d, 
      count(*) AS cnt 
    FROM products ee 
    LEFT JOIN reviews rr ON ee.productID = rr.productID 
    GROUP BY ee.productID) x ON e.productID = x.productID 
WHERE e.hidden = 0 
    AND e.datelive != -1 
GROUP BY e.productID HAVING COUNT(*) >= 5 
UNION 
SELECT e.productID, 
     (min(x.a)/(min(x.cnt)*1.0)+ min(x.b)/(min(x.cnt)*1.0)+ min(x.c)/(min(x.cnt)*1.0)+ min(x.d)/(min(x.cnt)*1.0))/4 AS score, 
     '2' AS SortOrder 
FROM products e 
LEFT JOIN reviews r ON r.productID = e.productID 
LEFT JOIN 
    (SELECT ee.productID, 
      sum(rr.a) AS a, 
      sum(rr.b) AS b, 
      sum(rr.c) AS c, 
      sum(rr.d) AS d, 
      count(*) AS cnt 
    FROM products ee 
    LEFT JOIN reviews rr ON ee.productID = rr.productID 
    GROUP BY ee.productID) x ON e.productID = x.productID 
WHERE e.hidden = 0 
    AND e.datelive != -1 
GROUP BY e.productID HAVING COUNT(*) < 5 
ORDER BY SortOrder ASC, 
     score DESC