GROUP BY
The aggregate functions of the last lesson turn a whole table into one row. But often the question is "how many for each…": how many products are in each category? You could count one category at a time with WHERE, but it's tedious:
1SELECT COUNT(*) FROM products WHERE category = 'Kitchen';2SELECT COUNT(*) FROM products WHERE category = 'Stationery';
| COUNT(*) |
|---|
| 2 |
| COUNT(*) |
|---|
| 2 |
4 categories take 4 queries, and with more categories you'd never finish. GROUP BY does it in one.
GROUP BY
GROUP BY column puts the rows that have the same value in that column into one group, and the aggregate functions are worked out once in each group:
1SELECT category, COUNT(*)2FROM products3GROUP BY category4ORDER BY category;
| category | COUNT(*) |
|---|---|
| Bags | 2 |
| Electronics | 4 |
| Kitchen | 2 |
| Stationery | 2 |
Press Step and watch: first the 10 products, then GROUP BY gathers them into 4 piles by category, each pile becomes one row of the result, and COUNT(*) counts the rows in that pile.
Don't leave out ORDER BY: after grouping, MySQL doesn't promise any particular order.
One row per group
One SELECT can hold several aggregate functions, each worked out once per group:
1SELECT category,2 COUNT(*) AS product_count,3 MIN(price) AS cheapest,4 MAX(price) AS dearest,5 SUM(stock) AS total_stock6FROM products7GROUP BY category8ORDER BY category;
| category | product_count | cheapest | dearest | total_stock |
|---|---|---|---|---|
| Bags | 2 | 11.00 | 39.90 | 40 |
| Electronics | 4 | 8.50 | 59.00 | 245 |
| Kitchen | 2 | 9.90 | 12.00 | 100 |
| Stationery | 2 | 4.50 | 6.00 | 200 |
The grouping column (category) has just one value in each group, so it can go in SELECT; each aggregate also gives just one value per group. Every row of the result is one group.
Ranking the groups
How many orders has each customer placed? Group by customer, then sort by the count, most first, and by customer number when the counts are equal:
1SELECT customer_id, COUNT(*) AS order_count2FROM orders3GROUP BY customer_id4ORDER BY order_count DESC, customer_id;
| customer_id | order_count |
|---|---|
| 1 | 3 |
| 2 | 2 |
| 4 | 2 |
| 5 | 2 |
| 3 | 1 |
| 7 | 1 |
| 8 | 1 |
Customer 1 placed 3 orders, the most. ORDER BY can use an alias given in SELECT; lesson 10 explains why.
Customers 6, 9 and 10, who never ordered, aren't in the result: the orders table has no rows for them, so there is no group for them either.
The total of each order
In order_items, one order has several rows. Group by order_id and add up "quantity × unit price" in each group, and you get the amount of each order:
1SELECT order_id,2 SUM(quantity) AS items,3 SUM(quantity * unit_price) AS total4FROM order_items5GROUP BY order_id6ORDER BY order_id;
| order_id | items | total |
|---|---|---|
| 1 | 4 | 19.50 |
| 2 | 1 | 39.90 |
| 3 | 3 | 76.00 |
| 4 | 1 | 15.00 |
| 5 | 4 | 43.80 |
| 6 | 5 | 22.50 |
| 7 | 3 | 61.90 |
| 8 | 1 | 59.00 |
| 9 | 4 | 21.00 |
| 10 | 2 | 23.50 |
| 11 | 1 | 12.00 |
| 12 | 4 | 39.60 |
18 rows of order lines become 12 rows, one per order.
An order's status is one of three: shipped, pending, cancelled. How many rows does the result have?
1SELECT status, COUNT(*)2FROM orders3GROUP BY status;
GROUP BY status puts the orders with the same status in one group: 3 statuses, 3 groups, one row each. Which of the 3 rows comes first is anyone's guess without an ORDER BY.
Grouping by several columns
GROUP BY can take several columns; rows form one group only when all of them are equal. Each customer's orders, counted separately by status:
1SELECT customer_id, status, COUNT(*)2FROM orders3GROUP BY customer_id, status4ORDER BY customer_id, status;
| customer_id | status | COUNT(*) |
|---|---|---|
| 1 | pending | 1 |
| 1 | shipped | 2 |
| 2 | pending | 1 |
| 2 | shipped | 1 |
| 3 | shipped | 1 |
| 4 | cancelled | 1 |
| 4 | pending | 1 |
| 5 | shipped | 2 |
| 7 | shipped | 1 |
| 8 | shipped | 1 |
Customer 1 has 2 shipped orders and 1 pending, so they make two rows.
NULL forms a group of its own, too. Group the employees by their manager to count how many people each one manages:
1SELECT manager_id, COUNT(*)2FROM employees3GROUP BY manager_id4ORDER BY manager_id;
| manager_id | COUNT(*) |
|---|---|
| NULL | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
The group whose manager_id is NULL is the manager herself, who has no manager.
What SELECT can hold
Once you group, SELECT can hold only two kinds of things: the grouping columns and aggregate functions. Any other column gives an error:
1SELECT category, name, COUNT(*)2FROM products3GROUP BY category;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'town.products.name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
ERROR 1055: name isn't in the GROUP BY. The Electronics group has 4 products and 4 names, yet only one row in the result: which name should it show? MySQL won't pick one for you.
The fix depends on what you want: for the numbers per group, drop name; for one row per product, don't group; for "one" name per group, pick it with an aggregate, such as MIN(name).
Tip: Some databases (and very old MySQL) don't give this error and just pick some name. The result may look right, but only by luck; don't rely on it.
Practice
Write the query, then press Check. A hint costs nothing; the answer is there when you need it.
Customers per city
✓Get how many customers each city has: two columns, city and customers, sorted by city.
| city | customers |
|---|---|
| Berlin | 2 |
| London | 3 |
| Paris | 2 |
| Sydney | 1 |
| Tokyo | 2 |
1SELECT city FROM customers;Units sold per product
✓From order_items, get how many of each product were sold in all: two columns, product_id and sold, sorted by product_id.
| product_id | sold |
|---|---|
| 1 | 10 |
| 2 | 3 |
| 3 | 2 |
| 4 | 3 |
| 5 | 2 |
| 7 | 3 |
| 8 | 6 |
| 9 | 2 |
| 10 | 2 |
1SELECT product_id, quantity FROM order_items;Nobody has bought the desk lamp (product 6), so it isn't in the result.
Fix it: ERROR 1055
✓This should give the number of people and the highest salary for each job title, highest salary first, but it gives ERROR 1055. Fix it; the columns are title, COUNT(*), MAX(salary) (ORDER BY can use an aggregate too, sorting by each group's value).
| title | COUNT(*) | MAX(salary) |
|---|---|---|
| Manager | 1 | 6000 |
| Sales lead | 1 | 4500 |
| Warehouse lead | 1 | 4200 |
| Sales | 2 | 3300 |
| Packer | 1 | 2800 |
1SELECT title, name, COUNT(*), MAX(salary)2FROM employees3GROUP BY title4ORDER BY MAX(salary) DESC;
What you learned
GROUP BY columnputs rows with the same value in one group; aggregates are worked out per group, one row per group.GROUP BYcan take several columns, and rows group together only when all are equal; NULL forms its own group.- Groups come in no particular order; fix it with
ORDER BY. SELECTcan hold only the grouping columns and aggregates; another column givesERROR 1055.