Qual é a diferença entre HAVING e WHERE?


261

Eu devo estar pesquisando no caminho errado ou estou tendo um momento estúpido no tempo.

Qual é a diferença entre HAVINGe WHEREem umSQL SELECT declaração?

EDIT: Marquei a resposta de Steven como a correta, pois continha as principais informações no link:

Quando GROUP BYnão é usado, HAVINGcomporta-se como uma WHEREcláusula

A situação em que eu tinha visto a situação WHEREnão teve GROUP BYe é onde minha confusão começou. Obviamente, até que você saiba disso, não poderá especificá-lo na pergunta.


44
A linha que você citar não é a chave. O bit principal, como wcm apontou , é que HAVINGé um filtro de pós-agregação, enquanto que WHEREé um filtro de pré-agregação.
25412 Nick Chammas

esse link me ajudou a entendê-lo melhor mais do que todos os comentários abaixo, e pensei que alguém poderia obter ajuda com este codeproject.com/Articles/25258/…
Lijin Durairaj

Respostas:


94

HAVING especifica uma condição de pesquisa para um grupo ou uma função agregada usada na instrução SELECT.

Fonte


369

HAVING: é usado para verificar as condições após a agregação.
ONDE: é usado para verificar as condições antes a agregação ocorra.

Este código:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City

Fornece uma tabela de todas as cidades em MA e o número de endereços em cada cidade.

Este código:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City
Having Count(1)>5

Fornece uma tabela de cidades em MA com mais de 5 endereços e o número de endereços em cada cidade.


7
Essa deve ser a resposta aceita. A distinção entre "ter" e "onde" torna isso imediatamente claro.
Paul

27

Diferença número um para mim: se HAVINGfosse removido da linguagem SQL, a vida continuaria mais ou menos como antes. Certamente, as consultas de uma minoria precisariam ser reescritas usando uma tabela derivada, CTE, etc., mas seriam mais fáceis de entender e manter como resultado. Talvez o código otimizador dos fornecedores precise ser reescrito para dar conta disso, novamente uma oportunidade de aprimoramento no setor.

Agora considere por um momento remover WHEREdo idioma. Dessa vez, a maioria das consultas existentes precisaria ser reescrita sem uma construção alternativa óbvia. Os codificadores precisariam ser criativos, por exemplo, junção interna a uma tabela conhecida por conter exatamente uma linha (por exemplo, DUALno Oracle) usando a ONcláusula para simular a WHEREcláusula anterior . Tais construções seriam inventadas; seria óbvio que havia algo faltando no idioma e a situação seria pior como resultado.

TL; DR, poderíamos perder HAVINGamanhã e as coisas não seriam piores, possivelmente melhores, mas não se pode dizer o mesmo WHERE.


A partir das respostas aqui, parece que muitas pessoas não percebem que uma HAVINGcláusula pode ser usada sem uma GROUP BYcláusula. Nesse caso, a HAVINGcláusula é aplicada a toda a expressão da tabela e requer que apenas constantes apareçam na SELECTcláusula. Normalmente, a HAVINGcláusula envolve agregados.

Isso é mais útil do que parece. Por exemplo, considere esta consulta para testar se a namecoluna é exclusiva para todos os valores em T:

SELECT 1 AS result
  FROM T
HAVING COUNT( DISTINCT name ) = COUNT( name );

Existem apenas dois resultados possíveis: se a HAVINGcláusula for verdadeira, o resultado será uma única linha contendo o valor 1; caso contrário, o resultado será o conjunto vazio.


Isso seria equivalente a "SELECT COUNT (nome DISTINCT) = COUNT (nome) FROM T"?
MSpreij

@MSpreij Não sei se isso funciona para você, mas ele não funciona no servidor SQL 2005, mas o primeiro se faz
Joe

22

A cláusula HAVING foi adicionada ao SQL porque a palavra-chave WHERE não pôde ser usada com funções agregadas.

Confira este link do w3schools para obter mais informações

Sintaxe:

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value

Uma consulta como esta:

SELECT column_name, COUNT( column_name ) AS column_name_tally
  FROM table_name
 WHERE column_name < 3
 GROUP 
    BY column_name
HAVING COUNT( column_name ) >= 3;

... pode ser reescrito usando uma tabela derivada (e omitindo a HAVING) assim:

SELECT column_name, column_name_tally
  FROM (
        SELECT column_name, COUNT(column_name) AS column_name_tally
          FROM table_name
         WHERE column_name < 3
         GROUP 
            BY column_name
       ) pointless_range_variable_required_here
 WHERE column_name_tally >= 3;

3
Você perdeu um pouco o ponto: HAVINGfoi adicionado porque as tabelas derivadas não foram adicionadas à linguagem e até que elas fossem SQL não estavam completas em termos relacionais e, uma vez que inevitavelmente se HAVINGtornaram redundantes.
onedaywhen

21

A diferença entre os dois está no relacionamento com a cláusula GROUP BY:

  • ONDE vem antes de GROUP BY; O SQL avalia a cláusula WHERE antes de agrupar registros.

  • TENDO vem depois de GROUP BY; SQL avalia HAVING após agrupar registros.

selecionar diagrama de instruções

Referências


Como GROUP BY e HAVING são opcionais, o diagrama mostra os dois casos, basta seguir as setas.
Paul Sweatte

Exemplo de consulta da minha resposta a esta pergunta: SELECT 1 AS result FROM T HAVING...- no seu diagrama não consigo HAVINGpassar sem passar, GROUP BYmas minha consulta perfeitamente válida e útil não tem GROUP BY. Ponto secundário: você não tem a opção de incluir valores literais na SELECTcláusula.
usar o seguinte código

@onedaywhen Como você conhece o GROUP BY implícito, por que você não o mencionou? Você sabe se esse comportamento é o que você está esperando ou não?
Paul Sweatte

Acho que você está me citando fora de contexto. A pergunta era sobre o aparente desvio do mySQL do padrão, mas o último parágrafo da minha resposta descreve o comportamento do padrão, e o último faz alusão à "cláusula implícita do GROUP BY mencionada em outras respostas ". Você está dizendo que seu diagrama pretende descrever (todos) comportamentos implícitos? Não seria mais útil manter apenas o código que você precisa escrever para obter o comportamento desejado?
precisa saber é o seguinte

... Não sei a que comportamento você está se referindo no segundo link. O resultado desejado é que você corrija o diagrama para mostrar o caminho (explícito) válido que mencionei. Pense nisso: o diagrama cobre uma consulta inteira, mas a pergunta está interessada apenas na WHERE->HAVINGparte, por isso acho que merece muita atenção aos detalhes. Se você acha que minha resposta está errada, edite-a ou publique uma correção sugerida nos comentários.
precisa saber é o seguinte

12

HAVINGé usado quando você está usando um agregado como GROUP BY.

SELECT edc_country, COUNT(*)
FROM Ed_Centers
GROUP BY edc_country
HAVING COUNT(*) > 1
ORDER BY edc_country;

8

WHERE é aplicado como uma limitação no conjunto retornado pelo SQL; ele usa oeprations e índices do conjunto interno do SQL e, portanto, é a maneira mais rápida de filtrar os conjuntos de resultados. Sempre use WHERE sempre que possível.

É necessário ter alguns filtros agregados. Ele filtra a consulta APÓS o sql ter recuperado, montado e classificado os resultados. Portanto, é muito mais lento que WHERE e deve ser evitado, exceto nas situações que o exigem.

O SQL Server permitirá que você use o HAVING mesmo quando WHERE seria muito mais rápido. Não faça isso.


O suporte para tabelas derivadas na linguagem SQL significa que sua afirmação "É necessário ter alguns filtros agregados" é falsa.
onedaywhen

1
Este é um bom ponto. Nos três anos desde que escrevi essa resposta, certamente migrei para o uso de tabelas derivadas, onde anteriormente eu teria usado o HAVING. Ainda não pensei na questão de ter ou não ainda alguns casos de uso que fazem sentido. Também não sei se uma tabela derivada terá um desempenho universal melhor que o HAVING.
Davidcl

7

A cláusula WHERE não funciona para funções agregadas
significa: você não deve usar como este bônus: nome da tabela

SELECT name  
FROM bonus  
GROUP BY name  
WHERE sum(salary) > 200  

AQUI Em vez de usar a cláusula WHERE, você deve usar HAVING ..

sem usar a cláusula GROUP BY, a cláusula HAVING funciona como a cláusula WHERE

SELECT name  
FROM bonus  
GROUP BY name  
HAVING sum(salary) > 200  

4

Diferença entre preto e branco WHEREe HAVINGcláusula:

A principal diferença entre WHEREe a HAVINGcláusula é, WHEREé usada para operações de linha e HAVINGé usada para operações de coluna.

Por que precisamos de HAVINGcláusula?

Como sabemos, funções agregadas só podem ser executadas em colunas; portanto, não podemos usar funções agregadas na WHEREcláusula. Portanto, usamos funções agregadas na HAVINGcláusula.


2

Quando GROUP BYnão é usado, as cláusulas WHEREe HAVINGsão essencialmente equivalentes.

No entanto, quando GROUP BYé usado:

  • A WHEREcláusula é usada para filtrar registros de um resultado. A filtragem ocorre antes de qualquer agrupamento ser feito.
  • A HAVINGcláusula é usada para filtrar valores de um grupo (ou seja, para verificar condições após a agregação em grupos ter sido executada).

Recurso daqui


ter e onde não são essencialmente equivalentes. dará erro durante a execução. é inválido na cláusula HAVING porque não está contida em uma função agregada ou na cláusula GROUP BY.
Nagendra Kumar

2

Uma maneira de pensar nisso é que a cláusula having é um filtro adicional para a cláusula where.

Uma cláusula WHERE é usada para filtrar registros de um resultado. O filtro ocorre antes de qualquer agrupamento ser feito. Uma cláusula HAVING é usada para filtrar valores de um grupo


1

Em uma consulta Agregada, (Qualquer consulta em que uma função agregada é usada) Predicados em uma cláusula where são avaliados antes que o conjunto de resultados intermediários agregados seja gerado,

Predicados em uma cláusula Having são aplicados ao conjunto de resultados agregados APÓS que ele foi gerado. É por isso que as condições predicadas dos valores agregados devem ser colocadas na cláusula Having, não na cláusula Where e por que você pode usar aliases definidos na cláusula Select em uma cláusula Having, mas não na cláusula Where.


1

Eu tive um problema e descobri outra diferença entre WHEREe HAVING. Ele não age da mesma maneira em colunas indexadas.

WHERE my_indexed_row = 123 mostrará linhas e executará automaticamente um "ORDER ASC" em outras linhas indexadas.

HAVING my_indexed_row = 123 mostra tudo, desde a linha "inserida" mais antiga até a mais recente, sem pedidos.


Como você sabe que essa é uma diferença definida entre os dois, em vez de um acidente de implementação do servidor SQL específico que você estava usando?
JdeBP

Acabei de o testar no MariaDB. Eu acho que foi o servidor SQL que eu estava usando há 8 anos que produziu resultados diferentes.
Simmoniz 14/11/19

0

A partir daqui .

o padrão SQL requer que HAVING faça referência apenas a colunas na cláusula GROUP BY ou colunas usadas em funções agregadas

em oposição à cláusula WHERE que é aplicada às linhas do banco de dados


A fonte diz: "O uso das posições da coluna foi descontinuado porque a sintaxe foi removida do padrão SQL". Infelizmente, isso está errado: nada é removido do Padrão, e, ironicamente, é o motivo pelo qual ainda temos HAVINGdécadas depois que ele foi 'reprovado' por tabelas derivadas.
Onedaywhen

Ligeiramente pedante, mas a citação não está correta, por exemplo, considere SELECT 1 FROM T HAVING COUNT(*) >= 1;- não faz referência a colunas na GROUP BYcláusula (não há nenhuma) nem colunas em funções agregadas (a consulta não faz referência a nenhuma coluna).
Onedaywhen

0

Enquanto trabalhava em um projeto, essa também foi minha pergunta. Como mencionado acima, o HAVING verifica a condição no resultado da consulta já encontrado. Mas WHERE é para verificar a condição enquanto a consulta é executada.

Deixe-me dar um exemplo para ilustrar isso. Suponha que você tenha uma tabela de banco de dados como esta.

utilizável {int userid, datefield, int dailyincome}

Suponha que as seguintes linhas estejam na tabela:

1, 20-05-2011, 100

1, 21-05-2011, 50

1, 30-05-2011, 10

2, 30-05-2011, 10

2, 20-05-2011, 20

Agora, queremos obter os userids e sum(dailyincome)cujasum(dailyincome)>100

Se escrevermos:

SELECT userid, sum (dailyincome) FROM utilizável WHERE soma (dailyincome)> 100 GROUP BY userid

Isso será um erro. A consulta correta seria:

SELECT userid, sum (dailyincome) FROM utilizável GROUP BY userid TENDO soma (dailyincome)> 100


0

A cláusula WHERE é usada para comparar valores na tabela base, enquanto a cláusula HAVING pode ser usada para filtrar os resultados de funções agregadas no conjunto de resultados da consulta Clique aqui !


0

Quando GROUP BY não é usado, as cláusulas WHERE e HAVING são essencialmente equivalentes.

No entanto, quando GROUP BY é usado:

  • A cláusula WHERE é usada para filtrar registros de um resultado. A filtragem ocorre antes de qualquer agrupamento ser feito.
  • A cláusula HAVING é usada para filtrar valores de um grupo (ou seja, para verificar as condições após a agregação em grupos ter sido realizada).

-1

Eu uso HAVING para restringir uma consulta com base nos resultados de uma função agregada. EG selecione * no grupo blahblahblah com ALGO tendo contagem (ALGO)> 0


-1

Pode ser que o assunto "onde" seja uma linha, enquanto o assunto "tendo" seja um grupo. Estou certo?


3
Você deve ter certeza antes de postar uma resposta. Isso pode ser enganoso para os outros.
pippin1289
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.