How the HAVING
clause works in SQLite? My code works and returns the name and division of the highest paid person in each division. However, the use of the HAVING
clause does not make sense to me since it should simply filter the groups with a false value for max(salary)
:
CREATE TABLE salaries AS
SELECT 'Alpha' as name, 'computer' as division, 500 as salary UNION
SELECT 'Bravo', 'computer', 600 UNION
SELECT 'Charlie', 'accounting', 200 UNION
SELECT 'Delta', 'accounting', 300 UNION
SELECT 'Echo', 'management', 800 UNION
SELECT 'Foxtrot', 'management', 900;
SELECT name, division FROM salaries GROUP BY division HAVING max(salary);
Why does the above query produce the same output as this query:
SELECT name, division
FROM salaries AS s
WHERE salary = (
SELECT MAX(salary)
FROM salaries
WHERE division = s.division
);
However, the use of the HAVING clause does not make much sense to me since it should simply filter out the groups with a false value for max(salary)
It would ONLY if the max(salary) per group was 0, according to:-
If a HAVING clause is specified, it is evaluated once for each group of rows as a boolean expression. If the result of evaluating the HAVING clause is false, the group is discarded. If the HAVING clause is an aggregate expression, it is evaluated across all rows in the group. If a HAVING clause is a non-aggregate expression, it is evaluated with respect to an arbitrarily selected row from the group. The HAVING expression may refer to values, even aggregate functions, that are not in the result. https://www.sqlite.org/lang_select.html#generation_of_the_set_of_result_rows
So if you used, for example:-
CREATE TABLE salaries AS
SELECT 'Alpha' as name, 'computer' as division, 500 as salary UNION
SELECT 'Bravo', 'computer', 600 UNION
SELECT 'Charlie', 'accounting', 200 UNION
SELECT 'Delta', 'accounting', 300 UNION
SELECT 'Echo', 'management', 800 UNION
SELECT 'Foxtrot', 'management', 900 UNION
SELECT 'Hotel', 'other', 0; /*<<<<<<<<<< ADDED for demo */
SELECT name, division, max(salary) AS msal FROM salaries GROUP BY division HAVING max(salary);
SELECT name, division, salary AS msal
FROM salaries AS s
WHERE salary = (
SELECT MAX(salary)
FROM salaries
WHERE division = s.division
);
i.e. the group for the other
division has been dropped as the max(salary) is false (0).
While the result of the second query includes the other
division:-