The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › Database
What does GROUP BY group, and what do COUNT and SUM count?
COUNT(*) and SUM(price) are aggregate functions that reduce many rows to one value. COUNT(*) returns how many rows there are, and SUM(price) returns the total when you add up all the prices. GROUP BY member is added after a SELECT statement, and it puts the rows that have the same member value into one group and makes the aggregation run once for each group. One group becomes one line of the result. In this lab you run the same aggregation on an orders table that holds 5 orders, and you remove GROUP BY member, add the ungrouped column id to SELECT, and add a WHERE condition, and you see how many lines the result has and what shape it takes.
Checked against real execution · Ran 6 combinations on H2 2.4.240 and checked against the results, and checked the rules against the MySQL documentation
CREATE TABLE orders (id INT PRIMARY KEY, member VARCHAR(20), price INT);
INSERT INTO orders VALUES (1, 'kim', 1000), (2, 'kim', 2000),
(3, 'lee', 500), (4, 'lee', 1500), (5, 'park', 3000);
SELECT member, COUNT(*), SUM(price)
FROM orders
-- GROUP BY: rows with the same member value form one group
GROUP BY member
ORDER BY member;
This was checked against real execution on H2 2.4.240 (in-memory database, JDBC). All 6 combinations were run, one statement at a time, with the whole SQL on the screen exactly as it is (CREATE TABLE, INSERT, SELECT, and the comment lines), and the number of rows that SELECT returned, the values of all the rows, whether an error occurred, and the kind of that error were checked against the model. The two combinations that caused an error gave H2 error code 90016 (a message saying that the id column must be in the GROUP BY list), and the screen shows only that kind, in English words. The values that the step sentences rely on were also checked separately on H2: the number of rows, 5, and the total, 8000, the ids of the rows whose price is 1000 or more (1, 2, 4, 5), the list of ids for each name (1 and 2 for kim, 3 and 4 for lee, 5 for park) and the list when WHERE is added (only 4 for lee), the number of different ids for each name, that there are 3 groups, and that the statement with MAX(id) runs without an error. What was different from what I expected: H2 did not give an error at the stage where it parses the statement with id written in it (prepareStatement), and gave the error while running, when there were different ids inside one group. So if only the park row was left, or if rows were left so that each group had only one id (ids 1, 3, 5), a statement of the same shape ran without an error. The sentences of the error step on the screen were written following this observation. The definitions and rules were checked by opening the documentation. In section 14.19.1 Aggregate Function Descriptions of the MySQL 8.4 documentation, it says that aggregate functions operate on sets of values, that using one without GROUP BY is equivalent to grouping all the rows, and that COUNT(*) counts the number of rows even if there are NULL values. In section 14.19.3 MySQL Handling of GROUP BY, it says that the SQL mode ONLY_FULL_GROUP_BY is enabled by default, that it rejects a statement that uses in SELECT a column that is not written in GROUP BY and is not functionally dependent on it, and that this is the same for a statement that uses an aggregate function without GROUP BY. In section 15.2.13 SELECT Statement, it says that the rows that meet the WHERE condition are selected, and that an aggregate function cannot be used in WHERE. The H2 grammar page (grammar.html) has no description of SELECT, so I opened SELECT on the Commands page. It says that GROUP BY groups the result by expressions, that if an aggregate function is used without GROUP BY all the rows are grouped together, and that in the logical order of execution WHERE comes before GROUP BY. All four documents were opened with a tool that summarizes web pages, and the original text was not checked letter by letter. The run was not checked against MySQL. So whether MySQL gives the same result and error for the same statements was not confirmed by running them, and according to the documentation, MySQL does not look at how many values id has but rejects the statement by looking only at the kind of the column written in it, so the conditions under which it gives an error differ from H2. The INSERT on the screen shows all 5 rows as they are. ORDER BY member at the end of SELECT was added so that the groups appear in member order, and if you remove GROUP BY member, the result has no member, so ORDER BY member was removed together with it. The step sentences explain, in order, the principle by which the result is made. How the database actually groups the rows is decided by the database, and what was confirmed by running is the result. This lab does not cover HAVING, grouping by two or more columns, columns that contain NULL, COUNT(column) and AVG, aggregation together with a join, or ANY_VALUE. HAVING, which sets a condition after aggregation, and the order in which SELECT is processed are covered in "SELECT processing order", how to rank rows without merging them in "Window functions", and aggregating the result of a join in "JOIN and GROUP BY".
Struck-through text was removed from the first version of the code; highlighted text was added.