2010-07-23 37 views
13

Tôi có hai bảng trong MySQL 5.1.38.Nhận SUM trong GROUP BY bằng JOIN bằng cách sử dụng MySQL

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 | 
+------------+--------+ 

Mục tiêu của tôi là lấy tổng giá của tất cả các sản phẩm có xếp hạng 5 sao trong mỗi bộ phận. Một cái gì đó như thế này.

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

Tôi muốn thực hiện việc này mà không cần truy vấn phụ nếu có thể. Lúc đầu, tôi đã thử tham gia với một số tiền().

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 | 
+------------+------------+ 

Như bạn có thể thấy giá cho bộ phận Đồ chơi không chính xác vì có hai xếp hạng 5 sao cho Xe đạp và do đó tính giá đó hai lần do tham gia.

Sau đó, tôi đã thử thêm riêng biệt vào tổng.

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 | 
+------------+---------------------+ 

Nhưng khi đó bộ phận quần áo bị tắt vì hai sản phẩm có cùng mức giá.

Hiện tại, công việc của tôi liên quan đến việc lấy một thứ gì đó độc đáo về sản phẩm (id) và sử dụng điều đó để làm cho giá độc đáo.

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 | 
+------------+-------------+ 

Nhưng điều này có vẻ giống như một hack ngớ ngẩn. Có cách nào tốt hơn để làm điều này mà không có truy vấn con không? Cảm ơn!

+2

Những gì bạn có chống lại các truy vấn con? –

+0

Tham gia và điều kiện của tôi phức tạp và năng động hơn và ORM (Bản ghi Hoạt động) của tôi không hỗ trợ tốt truy vấn phụ. – ryanb

+0

Làm thế nào để bạn biết từ bảng thứ hai yr mà bộ phận đánh giá belogs? –

Trả lời

16

sử dụng:

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 

về mặt kỹ thuật, điều này không sử dụng một subquery - nó sử dụng một bảng có nguồn gốc/inline vie w.

Đánh dấu trang này là wiki cộng đồng vì một số con khỉ cứ giảm xuống cho tôi mặc dù nó chính xác 100%.

+5

Đánh lừa con khỉ – Anax

+0

Cảm ơn Ngựa giống OMG! Điều này hoàn toàn giải quyết được một vấn đề tôi đã có ngày hôm nay. Trường hợp cụ thể của tôi yêu cầu một LEFT JOIN trên bảng dẫn xuất và có SUM bên trong định nghĩa bảng dẫn xuất, nhưng nó hoạt động rất tốt. Các kết quả EXPLAIN cũng không quá khủng khiếp, vì vậy chúng ta sẽ thấy nó có quy mô như thế nào. –

+0

Giải pháp này làm cho ngày của tôi! :) – jirislav

-1

Bạn có thể thực hiện hai truy vấn. truy vấn đầu tiên:

 
SELECT DISTINCT product_id FROM ratings WHERE rating = 5; 

Sau đó, dành mỗi người ID và tự đặt chúng trong truy vấn thứ hai:

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

Đây là công việc xung quanh vì không thể sử dụng truy vấn con. Nếu không có chúng, không có cách nào để loại bỏ các bản ghi trùng lặp gây ra bởi sự tham gia.

-1

Tôi không thể nghĩ ra bất kỳ cách nào để thực hiện việc này mà không cần truy vấn phụ ở đâu đó trong truy vấn. Bạn có lẽ có thể sử dụng một View để che giấu việc sử dụng truy vấn phụ.

Chặn điều đó, đặt cược tốt nhất của bạn có lẽ là tìm tập dữ liệu tối thiểu cần thiết để tính toán và thực hiện điều đó ở giao diện người dùng. Điều đó có thể phụ thuộc vào dữ liệu cụ thể của bạn hay không - số lượng hàng, v.v.

Tùy chọn khác (thực tế, có thể đây là cách tốt nhất ...) sẽ nhận ORM mới hoặc không có hoàn toàn;)

Quan điểm này sẽ cho phép bạn bỏ qua các subquery:

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

Lý do chính bạn gặp khó khăn khi tìm giải pháp là lược đồ như được trình bày về cơ bản là thiếu sót. Bạn không nên cho phép một bảng có hai hàng hoàn toàn trùng lặp nhau. Mọi bảng phải có phương tiện để nhận dạng duy nhất mỗi hàng ngay cả khi đó là sự kết hợp của tất cả các cột. Bây giờ, nếu chúng ta thay đổi bảng ratings để nó có một cột AUTO_INCREMENT gọi Id, vấn đề là dễ dàng hơn:

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

Thực ra tôi có một trường id tự động gia tăng trong ứng dụng thực sự phức tạp hơn nhiều. Tôi đã cố gắng đơn giản hóa mọi thứ như tôi có thể ở đây, nhưng dường như tôi đã đi quá xa bằng cách lấy ra ratings.id. Cảm ơn bạn đã đăng tùy chọn này! – ryanb

Các vấn đề liên quan