2015-03-08 70 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

相关问题