VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
GROUP BY treats the whole table as 1 group and returns 1
row. GROUP BY splits the rows into groups first, so you get 1 row for each
one. It is how “how many films” becomes “how many films of each rating”.
Open the client with mysql -u root -p sakila before you start.
How GROUP BY works
GROUPING_COLUMN with the column whose values define the groups,
TABLE_NAME with the table, and AGGREGATE_FUNCTION(COLUMN_NAME) with what you
want worked out for each group.
The server sorts the rows into buckets, 1 per distinct value of the grouping
column, and runs the aggregate over each bucket separately. The result has as
many rows as there were distinct values.
GROUP BY goes after WHERE and before ORDER BY, which is also the order
the result is defined in: filter the rows, group what survived, then sort the
groups.
Examples
1) One row per value
rating has 5 distinct values, and the 5 counts add up to
1,000. The rows come out in the declared order of the ENUM rather than
alphabetically, which the SELECT DISTINCT lesson
explains.
2) Group on 2 columns
Name 2 columns and a group is a distinct pairing, not a value of each.SELECT DISTINCT rating, rental_rate returns, with a count attached to each
row.
3) Filter the rows before grouping
WHERE runs first, so the counts are over the rows that survived it.
WHERE
removes every one of its rows.
4) Group on something you computed
The grouping column does not have to be a column. Any expression works, and you can name it with an alias and group on that.GROUP BY accepts an alias from the select list, which WHERE does not. This
is how a report gets grouped by month: compute the month, group on it.
5) Group over a join
Grouping is most useful once the rows come from more than 1 table. This counts each customer’s payments.customer_id is in the GROUP BY as well as
last_name, because 2 customers can share a surname and you want them counted
apart.
Every selected column must be grouped or aggregated
A group is many rows. Asking for a column that is neither the grouping column nor inside an aggregate asks the server which of those many rows to show, and it has no answer. Theonly_full_group_by setting, which is on by default, is
what makes the server say so rather than guess.
ERROR 1055 names the column it could not resolve, here title. There are 3
ways out, and which is right depends on what you meant:
- Add the column to
GROUP BY, when you wanted finer groups. - Wrap it in an aggregate such as
MIN(title), when any 1 value will do. - Move it out of the select list, when you did not need it.
only_full_group_by turned off the same query runs and returns an
arbitrary title, chosen by whatever plan the server picked. The
MySQL GROUP BY performance guide covers that setting and
ANY_VALUE(), which is how you ask for an arbitrary row on purpose.
GROUP BY does not promise an order
The groups come back in whatever order the server found convenient. Every example here saysORDER BY because that is the only way to fix the order, the
same as with LIMIT.
Summary
- Use
GROUP BYto get 1 result row per distinct value instead of 1 in total. - Expect a group per distinct combination when you name several columns.
- Expect
WHEREto filter rows before the grouping happens. - Read
ERROR 1055as a column that is neither grouped nor aggregated. - Add
ORDER BYwhen the order of the groups matters.
See also
- Aggregate functions — what to work out per group
- HAVING — filtering the groups after they are built
- WITH ROLLUP — adding a total row under the groups
- MySQL GROUP BY performance — the temporary table this can build

