Alguns pontos importantes sobre o uso do SQL:
- Você não pode usar aliases de coluna na cláusula WHERE, mas pode usar na cláusula HAVING. Essa é a causa do erro que você recebeu.
- Você pode fazer sua contagem melhor usando um JOIN e GROUP BY do que usando subconsultas correlacionadas. Será muito mais rápido.
- Use a cláusula HAVING para filtrar grupos.
Aqui está a maneira como eu escreveria esta consulta:
SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;
Percebo que esta consulta pode pular o
JOIN
com t1, como na solução de Charles Bretana. Mas suponho que você queira que a consulta inclua algumas outras colunas de t1. Re:a pergunta no comentário:
A diferença é que o
WHERE
cláusula é avaliada em linhas, antes de GROUP BY
reduz grupos para uma única linha por grupo. O HAVING
cláusula é avaliada após a formação dos grupos. Então você não pode, por exemplo, alterar o COUNT()
de um grupo usando HAVING
; você só pode excluir o próprio grupo. SELECT t1.id, COUNT(t2.id) as num
FROM t1 JOIN t2 USING (id)
WHERE t2.attribute = <value>
GROUP BY t1.id
HAVING num > 5;
Na consulta acima,
WHERE
filtros para linhas que correspondem a uma condição e HAVING
filtros para grupos que têm pelo menos cinco contagem. O ponto que causa confusão na maioria das pessoas é quando elas não têm um
GROUP BY
cláusula, então parece como HAVING
e WHERE
são intercambiáveis. WHERE
é avaliado antes de expressões na lista de seleção. Isso pode não ser óbvio porque a sintaxe SQL coloca a lista de seleção em primeiro lugar. Assim, você pode economizar muito cálculo caro usando WHERE
para restringir as linhas. SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;
Se você usar uma consulta como a acima, as expressões na lista de seleção serão calculadas para cada linha , apenas para descartar a maioria dos resultados devido ao
HAVING
doença. No entanto, a consulta abaixo calcula a expressão apenas para a linha única correspondendo a WHERE
doença. SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;
Então, para recapitular, as consultas são executadas pelo mecanismo de banco de dados de acordo com uma série de etapas:
- Gerar conjunto de linhas da(s) tabela(s), incluindo todas as linhas produzidas por
JOIN
. - Avalie
WHERE
condições contra o conjunto de linhas, filtrando as linhas que não correspondem. - Cálculo de expressões na lista de seleção para cada um no conjunto de linhas.
- Aplicar aliases de coluna (observe que esta é uma etapa separada, o que significa que você não pode usar aliases em expressões na lista de seleção).
- Condense os grupos em uma única linha por grupo, de acordo com
GROUP BY
cláusula. - Avalie
HAVING
condições contra grupos, filtrando grupos que não correspondem. - Ordenar resultado, de acordo com
ORDER BY
cláusula.