## Having `WHERE` cannot work with aggregates, `HAVING` can. ```sql SELECT column_name(s) FROM table_name WHERE condition GROUP BY column_name(s) HAVING condition ORDER BY column_name(s); ``` (see: [W3Schools](https://www.w3schools.com/sql/sql_having.asp) and [this stackoverflow](https://stackoverflow.com/questions/301793/mysql-using-count-in-the-where-clause)). So e.g. if we wanted, naively, to do ```sql SELECT DISTINCT gid FROM `gd` WHERE COUNT(*) > 10 --- error ORDER BY lastupdated DESC ``` this wouldn't work. This is where we need `HAVING`: ```sql SELECT gid FROM `gd` GROUP BY gid HAVING COUNT(*) > 10 ORDER BY lastupdated DESC ``` Essentially, `WHERE` happens before aggregation, whereas `HAVING` happens after aggregation. See *Order of Execution* below. # Order of Execution (See [builtin.com](https://builtin.com/data-science/sql-order-of-execution)). These clauses are *not* evaluated in the order written, but rather in the order below. Importantly, column aliases created in the `SELECT` cannot be referred to by the `WHERE` and `HAVING` clauses. 1. `FROM/JOIN` 1. `WHERE` 1. `GROUP BY` 1. `HAVING` 1. `SELECT` 1. `ORDER BY` 1. `LIMIT/OFFSET`