Получить сумму в GROUP BY с JOIN, используя MySQL - PullRequest
13 голосов
/ 23 июля 2010

У меня есть две таблицы в MySQL 5.1.38.

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

Я бы хотел сделать это без подзапроса, если смогу.Сначала я попробовал объединение с суммой ().

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

Но тогда отдел одежды отключен, потому что два продукта имеют одинаковую цену.

В настоящее времяМой обходной путь заключается в том, чтобы взять что-то уникальное в продукте (идентификатор) и использовать его, чтобы сделать цену уникальной.

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

Но это похоже на глупый взлом.Есть ли лучший способ сделать это без подзапроса?Спасибо!

Ответы [ 4 ]

18 голосов
/ 23 июля 2010

Использование:

  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

Технически, это не использует подзапрос - он использует производную таблицу / встроенное представление.

Отмечая это как вики сообщества, потому что какая-то обезьяна продолжает понижать меня, хотя это на 100% правильно.

0 голосов
/ 23 июля 2010

Основная причина, по которой у вас возникают проблемы с поиском решения, заключается в том, что представленная схема в корне неверна.Вы не должны позволять таблице иметь две строки, которые полностью дублируют друг друга. Каждая таблица должна иметь средства для уникальной идентификации каждой строки, даже если она является комбинацией всех столбцов.Теперь, если мы изменим таблицу 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 голосов
/ 23 июля 2010

Я не могу придумать способ сделать это без подзапроса где-то в запросе.Возможно, вы могли бы использовать View, чтобы замаскировать использование подзапроса.

За исключением этого, вашей лучшей ставкой, вероятно, будет найти минимальный набор данных, необходимый для расчета, и сделать это во входной части.Возможно ли это, зависит от ваших конкретных данных - сколько строк и т. Д.

Другой вариант (на самом деле, может быть, это лучший ...) будет получить новый ORM или обойтись без него.в целом;)

Это представление позволит вам обойти подзапрос:

CREATE VIEW Distinct_Product_Ratings
AS
    SELECT DISTINCT
        product_id,
        rating
    FROM
        Ratings
0 голосов
/ 23 июля 2010

Вы можете сделать два запроса. Первый запрос:

SELECT DISTINCT product_id FROM ratings WHERE rating = 5;

Затем возьмите каждый из этих идентификаторов и вручную поместите их во второй запрос:

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

Это обходной путь для невозможности использовать подзапросы. Без них невозможно устранить дубликаты записей, вызванные объединением.

...