Reputation: 2265
I have the tables products and history and I need to group by name:
products = (id_product, name)
history = (id_history, id_product, amount)
I tried this SQL query but it isn't grouped by name:
SELECT
products.name,
sum(history.amount)
FROM history
INNER JOIN products ON history.id_product = products.id_product
GROUP BY
products.name,
history.amount,
history.id_history;
This is the result:
Upvotes: 2
Views: 27061
Reputation: 94859
This is no answer, but too long for a comment.
For readability's sake the product table should be first. After all it is products that we select from, plus a history sum that we can access via [left] join history ...
followed by an aggregation, or [left] join (<history aggregation query>)
, or a subselect in the select clause.
Another step to enhance readability is the use of alias names.
select p.name, coalesce(sum(h.amount), 0) as total
from products p
left join history h on h.id_product = p.id_product
group by p.name
order by p.name;
select p.name, coalesce(h.sum_amount, 0) as total
from products p
left join
(
select sum(h.amount) as sum_amount
from history
group by id_product
) h on h.id_product = p.id_product
order by p.name;
select
name,
(select sum(amount) from history h where h.id_product = p.id_product) as total
from products p
order by p.name;
And as you were confused on how to use GROUP BY
, here is an explanation: GROUP BY ___
means you want one result row per ___
. In your original query you had GROUP BY products.name, history.amount, history.id_history
saying you wanted one result row per name, amount, and id, while you actually wanted one row per name only, i.e. GROUP BY products.name
.
Upvotes: 3
Reputation: 13179
You should only be grouping by the attributes you need to be aggregated. In this case, you need only products.name
.
SELECT
products.name,
sum(history.amount) AS [Amount]
FROM history
INNER JOIN products ON history.id_product = products.id_product
GROUP BY
products.name;
If you need to include products without history (assuming sum should be 0 instead of null
in this case), then you can use an OUTER JOIN
instead of INNER JOIN
to include all products:
SELECT
products.name,
COALESCE(sum(history.amount), 0) AS [Amount]
FROM history
RIGHT OUTER JOIN products ON history.id_product = products.id_product
GROUP BY
products.name;
Upvotes: 2