2015-03-08 73 views
1

我想爲每個客戶找到他們沒有購買的產品,以及哪些產品具有最高的評分。找到客戶沒有購買的產品的平均評分

例如,在下表中,約翰已經購買了物品1和2,但沒有購買3,4或5.產品3和5沒有評分,因此它們不會被包括在內,但產品4應該包括在內,因爲它是約翰沒有購買的最高評價項目。

這裏是我的一些樣本數據表結構:

客戶

id | customer 
----|--------- 
1 | john 
2 | jenkins 
3 | jane 
4 | janet 

產品

id | description 
----|--------- 
1 | deoderant 
2 | soap 
3 | shampoo 
4 | razor 
5 | sponge 

訂單

customer_id | product_id 
-------------|--------- 
1   | 1 
1   | 2 
2   | 3 
2   | 4 
3   | 5 

customer_id | product_id | rate 
-------------|------------|------- 
1   | 1   | 3 
2   | 2   | 2 
2   | 4   | 3 
4   | 2   | 4 
+0

你想爲所有客戶的所有此類產品的列表,或只爲特定的客戶? – eggyal 2015-03-08 17:23:47

+0

對於顧客還沒有購買但評價過的所有產品。 – Dino 2015-03-08 17:24:38

+0

您是否想要爲所有客戶提供所有此類產品的清單,還是隻爲特定客戶提供? – eggyal 2015-03-08 17:25:37

回答

1

我開始拼湊在一起之前寫幾個子查詢。我個人的建議是在整個解決方案之前總是將問題分解成更小的一部分。

例如,我需要知道的一件事是每個客戶都沒有購買的所有產品。我這樣做是由已經在順序表中存在的交叉連接的客戶和產品表(讓所有配對),除去對,是這樣的:

-- Get all customer/product pairings where customer_product 
-- does not exist in orders table 
SELECT c.id, p.id 
FROM customer c 
CROSS JOIN product p 
WHERE (c.id, p.id) NOT IN (SELECT * FROM orders) 
ORDER BY c.id; 

我也寫了一個子查詢,以獲得平均收視率每個產品。這個查詢將返回NULL,如果產品沒有等級:

SELECT p.id, AVG(r.rate) AS averageRating 
FROM product p 
LEFT JOIN rate r ON r.product_id = p.id 
GROUP BY p.id; 

現在,我可以包括這兩個子查詢和選擇客戶ID,產品ID,和他們沒有購買每個產品的評價:

SELECT t1.customerID, t1.productID, t2.averageRating 
FROM(
    SELECT c.id AS customerID, p.id AS productID 
    FROM customer c 
    CROSS JOIN product p 
    WHERE (c.id, p.id) NOT IN (SELECT * FROM orders) 
    ORDER BY c.id) t1 
JOIN(
    SELECT p.id AS productID, AVG(r.rate) AS averageRating 
    FROM product p 
    LEFT JOIN rate r ON r.product_id = p.id 
    GROUP BY p.id) t2 ON t2.productID = t1.productID; 

這是最難的部分。剩下的唯一要做的事就是進行一些聚合,以便從每個客戶沒有購買的商品中獲得最大的評分,然後在上面的查詢中加入聚合查詢,條件是最高評分與平均評分相匹配。所以,這裏是我已經把滔天查詢:

SELECT t1.customerID, t1.productID, t1.averageRating 
FROM(
    SELECT t1.customerID, t1.productID, t2.averageRating 
    FROM(
    SELECT c.id AS customerID, p.id AS productID 
    FROM customer c 
    CROSS JOIN product p 
    WHERE (c.id, p.id) NOT IN (SELECT * FROM orders) 
    ORDER BY c.id) t1 
    JOIN(
    SELECT p.id AS productID, AVG(r.rate) AS averageRating 
    FROM product p 
    LEFT JOIN rate r ON r.product_id = p.id 
    GROUP BY p.id) t2 ON t2.productID = t1.productID) t1 
JOIN(
    SELECT t1.customerID, MAX(t2.averageRating) AS maxRating 
    FROM(
    SELECT c.id AS customerID, p.id AS productID 
    FROM customer c 
    CROSS JOIN product p 
    WHERE (c.id, p.id) NOT IN (SELECT * FROM orders) 
    ORDER BY c.id) t1 
    JOIN(
    SELECT p.id AS productID, AVG(r.rate) AS averageRating 
    FROM product p 
    LEFT JOIN rate r ON r.product_id = p.id 
    GROUP BY p.id) t2 ON t2.productID = t1.productID 
    GROUP BY t1.customerID) t2 ON t2.customerID = t1.customerID AND t2.maxRating = t1.averageRating 
ORDER BY t1.customerID; 

這裏是從MySQL工作臺結果的快照: enter image description here

要注意的重要一點是,我並沒有消除領帶。因此,例如,客戶2沒有購買產品1或2並且它們具有相同的評級,因此返回兩行。

我在MySQL的測試,因爲SQL小提琴是行不通的,但我得到了工作,所以這裏是一個Fiddle例如,如果你喜歡的。

+0

嘗試測試這個,但是我總是收到錯誤消息,指出「操作數應該包含2列」 – Dino 2015-03-08 19:27:17

+0

@Dino在哪一行?您的實際訂單表是否有兩列以上?這會使我的子查詢在那裏我寫SELECT * FROM訂單。您可能需要改變,要卡斯特選擇,產品從接單。 – AdamMc331 2015-03-08 19:29:05

+1

啊訂單上有價格爲好,讓我檢查,我沒有改變過包括CUSTOMER_ID和PRODUCT_ID和我由於我對價格不感興趣,所以沒有工作。 – Dino 2015-03-08 19:43:46

1

如果你想爲一個客戶這樣做,只是用order bylimit

select c.*, r.* 
from customers c cross join 
    (select r.product_id, avg(rating) avgr 
     from rating r 
     group by r.product_id 
    ) r left join 
    orders o 
    on o.customer_id = c.customer_id and 
     o.product_id = r.product_id 
where c.customer_id = @customerid and o.product_id is null 
order by r.avgr desc 
limit 1; 

如果你想爲所有客戶一次,它更復雜一些。一種方法是用substring_index()/group_concat()招:

select c.*, 
     substring_index(group_concat(r.product_id order by avgr desc), ',', 1) as product_id 
from customers c cross join 
    (select r.product_id, avg(rating) avgr 
     from rating r 
     group by r.product_id 
    ) r left join 
    orders o 
    on o.customer_id = c.customer_id and 
     o.product_id = r.product_id 
where c.customer_id = @customerid and o.product_id is null 
group by c.customer_id; 
+1

我覺得你在你的'from'條款命名'orders'表之前已經省略'LEFT JOIN'。你的第二個查詢可能不應該在where子句中的'c.customer_id'上有一個過濾器? – eggyal 2015-03-08 17:59:53

+0

@eggyal是對的,你錯過了左連接關鍵字。但是,我使用左連接在工作臺中測試了這一點,這個結果非常好。 – AdamMc331 2015-03-08 19:00:03

+0

當我在訂單之前完成一個左連接時,我得不到結果:( – Dino 2015-03-09 08:55:43

相關問題