2014-10-28 32 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