2010-07-23 42 views
13

我在MySQL 5.1.38中有两个表。使用MySQL在GROUP BY中使用JOIN获得SUM

products 
+----+------------+-------+------------+ 
| id | name  | price | department | 
+----+------------+-------+------------+ 
| 1 | Fire Truck | 15.00 | Toys  | 
| 2 | Bike  | 75.00 | Toys  | 
| 3 | T-Shirt | 18.00 | Clothes | 
| 4 | Skirt  | 18.00 | Clothes | 
| 5 | Pants  | 22.00 | Clothes | 
+----+------------+-------+------------+ 

ratings 
+------------+--------+ 
| product_id | rating | 
+------------+--------+ 
|   1 |  5 | 
|   2 |  5 | 
|   2 |  3 | 
|   2 |  5 | 
|   3 |  5 | 
|   4 |  5 | 
|   5 |  4 | 
+------------+--------+ 

我的目标是获得所有产品的总价格,每个部门都有5星评级。像这样的东西。

+------------+-------------+ 
| department | total_price | 
+------------+-------------+ 
| Clothes | 36.00  | /* T-Shirt and Skirt */ 
| Toys  | 90.00  | /* Fire Truck and Bike */ 
+------------+-------------+ 

我想这样做没有子查询,如果我可以。起初,我试着用sum()来加入。

select department, sum(price) from products 
join ratings on product_id=products.id 
where rating=5 group by department; 
+------------+------------+ 
| department | sum(price) | 
+------------+------------+ 
| Clothes |  36.00 | 
| Toys  |  165.00 | 
+------------+------------+ 

正如你所看到的价格为玩具部门因为有自行车两个5星评级,因此计数是价格的两倍,由于加入不正确。

我然后尝试添加不同的总和。

select department, sum(distinct price) from products 
join ratings on product_id=products.id where rating=5 
group by department; 
+------------+---------------------+ 
| department | sum(distinct price) | 
+------------+---------------------+ 
| Clothes |    18.00 | 
| Toys  |    90.00 | 
+------------+---------------------+ 

但后来衣服部门关闭,因为两个产品共享相同的价格。

目前,我的解决方法包括采取独特的产品(id),并使用它来使价格独一无二。

select department, sum(distinct price + id * 100000) - sum(id * 100000) as total_price 
from products join ratings on product_id=products.id 
where rating=5 group by department; 
+------------+-------------+ 
| department | total_price | 
+------------+-------------+ 
| Clothes |  36.00 | 
| Toys  |  90.00 | 
+------------+-------------+ 

但是,这感觉就像这样一个愚蠢的黑客。没有子查询有没有更好的方法来做到这一点?谢谢!

+2

你有什么反对的子查询? – 2010-07-23 17:42:54

+0

我的连接和条件更加复杂和动态,而且我的ORM(活动记录)不能很好地支持子查询。 – ryanb 2010-07-23 17:45:09

+0

你怎么知道从第二个表到哪个部门评分? – 2010-07-23 17:46:05

回答

16

用途:

SELECT p.department, 
     SUM(p.price) AS total_price 
    FROM PRODUCTS p 
    JOIN (SELECT DISTINCT 
       r.product_id, 
       r.rating 
      FROM RATINGS r) x ON x.product_id = p.id 
          AND x.rating = 5 
GROUP BY p.department 

从技术上讲,这并不使用子查询 - 它使用派生表/直列争夺W上。

将此标记为社区维基cuz某些猴子保持downvoting我虽然它是100%正确的。

+5

打个小狗 – Anax 2010-07-23 18:23:18

+0

感谢OMG小马!这完美地解决了我今天遇到的一个问题。我的具体情况需要在派生表上使用LEFT JOIN,并在派生表定义中使用SUM,但它很好用。 EXPLAIN结果看起来并不太可怕,所以我们会看到它的规模。 – 2013-06-25 06:33:25

+0

这个解决方案使我的一天! :) – jirislav 2017-06-02 10:33:34

-1

你可以做两个查询。首先查询:

 
SELECT DISTINCT product_id FROM ratings WHERE rating = 5; 

然后,把每这些ID的,并手动将它们在第二个查询:

 
SELECT department, Sum(price) AS total_price 
FROM  products 
WHERE product_id In (1,2,3,4) 
GROUP BY department; 

这是变通为不能够使用子查询。没有它们,就无法消除由连接引起的重复记录。

-1

我想不出没有子查询查询中的任何方式。你也许可以使用View来屏蔽子查询的使用。

除非这样,否则最好的办法是找到计算所需的最小数据集并在前端执行此操作。是否可能取决于您的具体数据 - 多少行等。

其他选项(实际上,也许这是最好的......)将是获得一个新的ORM或完全没有它; )

这种观点将允许你绕过子查询:

CREATE VIEW Distinct_Product_Ratings 
AS 
    SELECT DISTINCT 
     product_id, 
     rating 
    FROM 
     Ratings 
0

您无法找到解决方案的主要原因是所提供的架构存在根本性缺陷。你不应该让一个表有两个完全相互重复的行。 每个表应该有一种方法来唯一标识每一行,即使它是所有列的组合。现在,如果我们改变ratings表,以便它有一个AUTO_INCREMENT列名为Id,这个问题很容易:

Select products.department, Sum(price) As total_price 
From products 
    Left Join ratings As R1 
     On R1.product_id = products.id 
      And R1.rating = 5 
    Left Join ratings As R2 
     On R2.product_id = R1.product_id 
      And R2.rating = R1.rating 
      And R2.Id > R1.Id 
Where R2.Id Is Null 
Group By products.department 
+0

其实我真的有一个自动递增的id字段在真正的应用程序,这是更复杂。我试图尽可能简化所有的事情,但是看起来我通过拿出ratings.id来做得太过分了。感谢您发布此选项! – ryanb 2010-07-23 22:57:31