I have a query like this:
SELECT t1.id,
(SELECT COUNT(t2.id)
FROM t2
WHERE t2.id = t1.id
) as num_things
FROM t1
WHERE num_things = 5;
The goal is to get the id of all the elements that appear 5 times in the other table. However, I get this error:
ERROR: column "num_things" does not exist
SQL state: 42703
I'm probably doing something silly here, as I'm somewhat new to databases. Is there a way to fix this query so I can access num_things
? Or, if not, is there any other way of achieving this result?
A few important points about using SQL:
Here's the way I'd write this query:
I realize this query can skip the
JOIN
with t1, as in Charles Bretana's solution. But I assume you might want the query to include some other columns from t1.Re: the question in the comment:
The difference is that the
WHERE
clause is evaluated on rows, beforeGROUP BY
reduces groups to a single row per group. TheHAVING
clause is evaluated after groups are formed. So you can't, for example, change theCOUNT()
of a group by usingHAVING
; you can only exclude the group itself.In the above query,
WHERE
filters for rows matching a condition, andHAVING
filters for groups that have at least five count.The point that causes most people confusion is when they don't have a
GROUP BY
clause, so it seems likeHAVING
andWHERE
are interchangeable.WHERE
is evaluated before expressions in the select-list. This may not be obvious because SQL syntax puts the select-list first. So you can save a lot of expensive computation by usingWHERE
to restrict rows.If you use a query like the above, the expressions in the select-list are computed for every row, only to discard most of the results because of the
HAVING
condition. However, the query below computes the expression only for the single row matching theWHERE
condition.So to recap, queries are run by the database engine according to series of steps:
JOIN
.WHERE
conditions against the set of rows, filtering out rows that don't match.GROUP BY
clause.HAVING
conditions against groups, filtering out groups that don't match.ORDER BY
clause.try this
I think you could just rewrite your query like so:
All the other suggestions would work, but to answer your basic question it would be sufficient to write
I'd like to mention that in PostgreSQL there is no way to use aliased column in having clause.
i.e.
SELECT usr_id AS my_id FROM user HAVING my_id = 1
Wont work.
Another example that is not going to work:
SELECT su.usr_id AS my_id, COUNT(*) AS val FROM sys_user AS su GROUP BY su.usr_id HAVING val >= 1
There will be the same error: val column is not known.
Im highliting this because Bill Karwin wrote something not really true for Postgres:
"You cannot use column aliases in the WHERE clause, but you can in the HAVING clause. That's the cause of the error you got."