You error is WHERE
instead of HAVING
, like Gordon pointed out.
But I suggest to rewrite your query like this:
SELECT id
, COALESCE(s.primarycount , 0) AS primarycount
, COALESCE(s.nonprimarycount, 0) AS nonprimarycount
FROM dino d
LEFT JOIN (
SELECT id
, count(*) FILTER (WHERE is_primary) AS primarycount
, count(*) FILTER (WHERE is_primary = false) AS nonprimarycount
FROM senator
GROUP BY id
) s USING (id)
WHERE (s.nonprimarycount > 9) IS NOT TRUE
ORDER BY nonprimarycount DESC, primarycount DESC;
Should be faster.
- It's typically (much) faster to aggregate before the join.
- Since we pushed the aggregation down into a subquery, we can now use
WHERE
in the outer SELECT
instead of HAVING
, removing your cause of error. Same performance, but simpler.
count(*)
is faster and equivalent for the case.
is_primary = true
is a noisy way of saying is_primary
.
WHERE (s.nonprimarycount > 9) IS NOT TRUE
is the same as WHERE (s.nonprimarycount < 10 OR s.nonprimarycount IS NULL)
.
- We can now get NULL for "no row in table
senator
". I default to 0
like your original does. If you want to display the difference instead, remove COALESCE
and use ORDER BY ... DESC NULLS LAST
to sort NULL values last.
- Notably, the (unqualified!) output column name will work in
ORDER BY
, even though it's the same as the input column name in the outer SELECT
because, quoting the manual:
If an ORDER BY
expression is a simple name that matches both an
output column name and an input column name, ORDER BY
will interpret
it as the output column name. This is the opposite of the choice that
GROUP BY
will make in the same situation. This inconsistency is made
to be compatible with the SQL standard.
If we can assume that every dino
has at least one row in senator
, we can simplify:
SELECT id
, s.primarycount
, s.nonprimarycount
FROM dino d
JOIN (
SELECT id
, count(*) FILTER (WHERE is_primary) AS primarycount
, count(*) FILTER (WHERE is_primary = false) AS nonprimarycount
FROM senator
GROUP BY id
) s USING (id)
WHERE s.nonprimarycount < 10
ORDER BY s.nonprimarycount DESC, s.primarycount DESC;
Now, the counts cannot be NULL.