Voltar para a lista de artigos Artigos
11 minutos de leitura

Qual é a diferença entre as cláusulas WHERE e HAVING em SQL?

medida que a quantidade de dados no mundo cresce a cada dia, aumenta a necessidade de gerenciar e consultar os dados de forma eficiente. SQL oferece maneiras de manipular e consultar dados em qualquer escala. Como parte importante disto, as cláusulas WHERE e HAVING permitem filtrar os dados conforme a necessidade, mas não são a mesma coisa. Explicaremos em detalhes as diferenças entre elas.

Uma das tarefas mais comuns na manipulação e consulta de dados é a filtragem usando as cláusulas WHERE e HAVING. Embora ambas filtrem os dados com base em condições e/ou funções definidas pelo usuário, existem diferenças importantes na forma como cada cláusula é executada.

Este artigo explica em detalhes quando usar WHERE ou HAVING. Explicaremos brevemente o fluxo lógico do processo de uma consulta SQL que inclui as cláusulas WHERE e/ou HAVING, seguidas de alguns cenários práticos e exemplos para que possamos resolver juntos.

Fluxo de Processo Lógico para Consultas com WHERE e HAVING

A ordem em que você escreve uma consulta SQL é diferente da ordem de execução. Vejamos o seguinte como um exemplo:

SELECT country_id, city, MIN(salary), MAX(salary) 
FROM hr.emp_details_view
WHERE country_id IN ('US', 'UK')
GROUP BY country_id, city
HAVING MIN(salary) < 15000
ORDER BY country_id; 

O fluxo lógico do processo de uma consulta SQL é diagramado abaixo.

Ordem de execução em consultas SQL

Figura 1: Ordem de execução nas consultas SQL.


  1. O processamento lógico de uma consulta SQL começa com uma instrução FROM, que reúne dados das tabelas listadas na consulta. Ela também pode conter uma cláusula JOIN que combina duas ou mais tabelas usando o operador ON.

    Note que as condições usadas na cláusula WHERE também podem ser usadas no operador ON da cláusula JOIN. Além disso, as tabelas combinadas usando condições no operador ON da cláusula JOIN também podem ser usadas na cláusula WHERE. Entretanto, deve-se usar um WHERE somente para condições que filtrem linhas individuais. Ele melhora a legibilidade da consulta e permite que o operador do ON trate apenas da combinação das tabelas, que é seu propósito.

  2. O próximo passo no fluxo lógico do processo é a cláusula WHERE, que filtra os registros para aqueles que atendem à(s) condição(ões) e/ou função(ões) definida(s) pelo usuário e os passa adiante.
  3. A cláusula WHERE é seguida pela cláusula GROUP BY, que agrupa os registros recebidos a partir da condição WHERE. Por exemplo, a(s) coluna(s) listada(s) na cláusula GROUP BY podem ser as equipes, e outras colunas são agregadas pela(s) função(ões) agregada(s) e atribuídas ao(s) grupo(s)/equipa(s) correspondente(s).
  4. A seguir é a cláusula HAVING, que filtra os grupos criados em GROUP BY em vez de registros individuais.
  5. Neste ponto, o processamento lógico vai para o comando SELECT. Ele avalia quais colunas serão enviadas para a saída. Também avalia quaisquer palavras-chave como UNIQUE, DISTINCT, e TOP, se incluídas.
  6. A cláusula ORDER BY é executada no final do fluxo do processo lógico. Ela ordena os dados pela(s) coluna(s) nela especificada(s) e em ordem ascendente por padrão.

Em primeiro lugar, o Essencial: Especificação das condições em WHERE e HAVING

Há uma ampla gama de operadores que nos ajudam a criar e combinar condições nas cláusulas WHERE e HAVING:

  • sinais de comparação: <, >, <=, >=, =, <>
  • teste de valor nulo: IS NULL, IS NOT NULL
  • wildcards: LIKE, '%=_'
  • teste de alcance: BETWEEN
  • teste de presença em um conjunto: IN
  • teste de existência: EXISTS
  • sinais de comparação quantificados: ALL, ANY, SOME
  • combinação lógica das condições: AND, OR, NOT

Os operandos em uma cláusula WHERE podem incluir colunas listadas em SELECT, exceto as colunas utilizadas em funções agregadas. Em contraste, HAVING filtra por valores resultantes da função agregada, como SUM(), COUNT(), e AVG(), entre outros.

Exemplos

As tabelas employee e emp_details_viewOs exemplos a seguir, mostrados parcialmente, são utilizados ao longo dos próximos exemplos.

SELECT * 
FROM hr.employees;
EMPLOYEE_IDLAST_NAMEMANAGER_IDHIRE_DATESALARYJOB_ID
101Kochhar10021-SEP-0517000AD_VP
102De Haan10013-JAN-0117000AD_VP
108Greenberg10117-AUG-0212008FI_MGR
103Hunold10203-JAN-069000IT_PROG
105Austin10325-JUN-054800IT_PROG
116Baida11424-DEC-052900PU_CLERK
117Tobias11424-JUL-052800PU_CLERK
145Russell10001-OCT-0414000SA_MAN
148Cambrault10015-OCT-0711000SA_MAN
SELECT * 
FROM hr.emp_details_view;
EMPLOYEE_IDLAST_NAMEFIRST_NAMESALARYDEPARTMENT_IDCOUNTRY_IDCITYLOCATION_ID
103HunoldAlexander900060USSouthlake1400
105AustinDavid480060USSouthlake1400
101KochharNeena1700090USSeattle1700
102De HaanLex1700090USSeattle1700
108GreenbergNancy12008100USSeattle1700
116BaidaShelli290030USSeattle1700
117TobiasSigal280030USSeattle1700
145RussellJohn1400080UKOxford2500
148CambraultGerald1100080UKOxford2500

Cenário I: A cláusula WHERE

A cláusula WHERE é utilizada para filtrar filas individuais de dados obtidos do banco de dados por SELECT. Os registros que não atendem à(s) condição(ões) WHERE não são incluídos na saída.

Vejamos um exemplo:

where age > 25 AND city='New York'

Ela passa apenas os registros cuja idade é maior que 25 anos e cujo city é Nova York.

Na sintaxe da consulta, a cláusula WHERE é usada diretamente após SELECT e FROM. Ela filtra linhas individuais - registros brutos, não agrupados - buscados pela consulta, para determinar quais registros devem ser passados para a cláusula GROUP BY.

Vamos examinar a saída da consulta abaixo, que usa a cláusula WHERE.

SELECT last_name, hire_date, manager_id 
FROM hr.employees
WHERE last_name LIKE '%a%' 
AND (hire_date BETWEEN '01-JAN-05' AND '01-JAN-07') 
AND manager_id IS NOT NULL;
LAST_NAMEHIRE_DATEMANAGER_ID
Baida24-DEC-05114
Kochhar21-SEP-05100
Tobias24-JUL-05114

O exemplo acima mostra as colunas last_name, hire_date, e manager_id da tabela hr.employee. A cláusula WHERE filtra a saída da seguinte forma:

  • last_name deve incluir uma letra "a" na mesma;
  • hire_date deve ser maior ou igual a 01-JAN-05 e menor ou igual a 01-JAN-07; e
  • manager_id deve ter um valor e não ser nulo.

Somente os registros que atendem as condições WHERE são apresentados na saída.

Vejamos outro exemplo a partir do mesmo cenário:

SELECT employee_id, salary, job_id 
FROM hr.employees
WHERE (salary < 3000 OR salary = 9000) 
AND job_id IN ('IT_PROG', 'FI_MGR', 'PU_CLERK'); 
EMPLOYEE_IDSALARYJOB_ID
1039000IT_PROG
1162900PU_CLERK
1172800PU_CLERK

Este exemplo produz as colunas employee_id, salary, e job_id da tabela hr.employee. A cláusula WHERE filtra a saída da seguinte forma:

  • salary deve ser inferior a 3000, ou deve ser igual a 9000; e
  • job_id deve ser igual a qualquer valor listado no operador IN.

Como na consulta anterior, a saída contém apenas os registros que atendem à condição WHERE.

Tenha em mente que WHERE não pode conter condições que incluam funções agregadas. Esse é o trabalho para HAVING.

Cenário II: A Cláusula HAVING

HAVING é usado para filtrar grupos de registros criados pela cláusula GROUP BY. Por esta razão, a cláusula HAVING deve seguir a cláusula GROUP BY. É semelhante à cláusula WHERE que filtra a saída SELECT, somente que WHERE filtra registros individuais enquanto HAVING filtra grupos.

Funções agregadas tais como SUM(), MAX(), MIN(), AVG(), e COUNT() são o foco da cláusula HAVING.

Vejamos isso em ação nos exemplos.

SELECT SUM(salary), department_id 
FROM hr.emp_details_view
GROUP BY department_id
HAVING SUM(salary) > 10000; 
SUM(SALARY)DEPARTMENT_ID
3400090
1380060
12008100
2500080

O exemplo acima lista os departamentos junto com a soma de todos os salários em cada departamento. Somente os department_ids cujos salários totais são maiores que 10000 são listados na saída. Aqueles que não cumprem a condição estabelecida pela cláusula HAVING são filtrados.

Vejamos outro exemplo:

SELECT COUNT(employee_id), job_id, salary
FROM hr.employees
WHERE salary > 12000
GROUP BY job_id, salary
HAVING COUNT(employee_id) < 10; 
COUNT(EMPLOYEE_ID)JOB_IDSALARY
1SA_MAN14000
2AD_VP17000
1FI_MGR12008

Esta consulta lista o número de funcionários para cada combinação de job_id e salário. A cláusula WHERE filtra os registros para aqueles com salários superiores a 12.000. A cláusula GROUP BY, que segue um WHERE, especifica o agrupamento por colunas não-agregadas job_id e salário. Finalmente, a cláusula HAVING especifica o valor agregado COUNT(employee_id) a ser inferior a 10.

Cenário III: A Cláusula GROUP BY

ONDE COM UM GROUP BY Cláusula

A cláusula WHERE deve ser sempre colocada antes de GROUP BY. Isto porque WHERE filtra linhas individuais de dados, não grupos de linhas. A cláusula GROUP BY retira as linhas individuais do resultado do filtro de nível de linha WHERE para criar grupos de linhas.

Aqui está um exemplo:

SELECT job_id, SUM(salary) 
FROM hr.employees
WHERE manager_id IN (100, 101, 102, 103)
GROUP BY job_id; 
JOB_IDSUM(SALARY)
AD_VP34000
FI_MGR12008
IT_PROG13800
SA_MAN25000

A consulta acima é avaliada da seguinte forma:

  1. A cláusula WHERE primeiro filtra os registros com manager_id que não são encontrados na lista que segue o operador IN.
  2. A cláusula GROUP BY então agrupa por job_id os registros que passaram a condição WHERE.

A consulta calcula os salários totais dos funcionários administrados por cada um dos gerentes especificados (manager_ids 100, 101, 102, 103). Os salários dos funcionários que se reportam a outros gerentes não são incluídos no cálculo deste total.

tendo um grupo de acordo com uma cláusula

A cláusula GROUP BY é freqüentemente utilizada com funções agregadas. Ela cria valores resumidos para as colunas listadas em GROUP BY.

Em contraste, HAVING sempre segue uma cláusula GROUP BY, já que HAVING trabalha com os grupos criados pelo GROUP BY.

Vamos considerar um caso usando HAVING no qual o GROUP BY não pode ser omitido. Isto é verdade se existem colunas listadas em SELECT que não são utilizadas pelas funções agregadas, tais como department_id no exemplo abaixo. Estas colunas não agregadas devem ser listadas em GROUP BY para agrupamento de dados.

SELECT avg(salary), department_id 
FROM hr.emp_details_view
GROUP BY department_id
HAVING avg(salary) < 15000; 
AVG(SALARY)DEPARTMENT_ID
285030
690060
12008100
1250080

No entanto, HAVING pode ser usado sem um GROUP BY que o acompanhe. Note que, neste caso, HAVING é aplicado a toda a saída do SELECT, tratando-o como um único grupo. O abaixo é um exemplo:

SELECT round(avg(salary))
FROM hr.emp_details_view
HAVING avg(salary) < 11000; 
ROUND(AVG(SALARY))
10056

A consulta retorna um único valor contendo a média de todos os salários. Note que a cláusula HAVING coloca um limite a este valor agregado. Se a média calculada fosse maior que 11000, a consulta não teria retornado nenhum registro.

O seguinte é um exemplo de pseudoagregação, na qual funções agregadas são utilizadas no lugar de um GROUP BY:

SELECT MIN(first_name), MIN(department_id), MAX(salary)
FROM hr.emp_details_view
HAVING MIN(salary) > 1000; 
MIN(FIRST_NAME)MIN(DEPARTMENT_ID)MAX(SALARY)
Alexander3017000

A função MIN() é utilizada aqui nas colunas first_name e department_id. Não está sendo chamada em um uso típico de funções agregadas, mas sim com o objetivo de evitar um GROUP BY. Neste caso, a saída é apenas um único registro de dados que consiste no valor mínimo para first_name, o valor mínimo para department_id, e o valor máximo para salário, cada um de toda a tabela. Observe que estes 3 valores podem ser provenientes de 3 registros diferentes, como é neste exemplo. Além disso, neste caso, se o salário mínimo para toda a tabela fosse 1000 ou menos, a consulta não retornaria nenhum registro.

Este exemplo particular é um pouco artificial para que possamos mostrar algo mais simples. Embora menos comum que GROUP BY, a pseudo-agregação pode ser usada em consultas que tratam todas as linhas incluídas como um único grupo.

O uso para HAVING com ou sem um GROUP BY pode variar de acordo com o banco de dados. Se você quiser saber mais sobre a cláusula GROUP BY, por favor visite o artigo GROUP BY Cláusula.

Cenário IV: Usando as duas cláusulas WHERE e HAVING em conjunto

A sintaxe para utilizar WHERE e HAVING em uma consulta segue a ordem específica apresentada abaixo:

  1. SELECT: seleciona as colunas do banco de dados a serem produzidas para o resultado.
  2. FROM: lista as tabelas a serem usadas na consulta.
  3. WHERE: filtra os registros individuais.
  4. GROUP BY: agrupa os registros com base na(s) coluna(s) especificada(s).
  5. HAVING: filtra os grupos definidos por GROUP BY.
  6. ORDER BY: ordena os registros de saída pela(s) coluna(s) especificada(s).

Vejamos um exemplo que utiliza todos os itens acima.

SELECT country_id, city, MIN(salary), MAX(salary) 
FROM hr.emp_details_view
WHERE country_id IN ('US', 'UK')
GROUP BY country_id, city
HAVING MIN(salary) < 15000
ORDER BY country_id; 
COUNTRY_IDCITYMIN(SALARY)MAX(SALARY)
UKOxford1100014000
USSeattle280017000
USSouthlake48009000

A consulta busca busca o mínimo salary e o máximo salary para cada combinação de city e country_id, este último limitado aos EUA e ao Reino Unido apenas pela condição WHERE.

Suponha que você tenha 10 registros com os EUA como o country_id, e dentro dele, há 5 registros com Nova Iorque como a cidade e outros 5 com Los Angeles como a cidade. Quando você executa a consulta acima, estes 10 registros se tornam 2 registros:

  • um registro para os EUA e Nova York, com seus salários mínimos e máximos,
  • outro recorde para os EUA e Los Angeles, também com seus salários mínimos e máximos.

Para maiores informações sobre as diferenças entre WHERE e HAVING, favor visitar o artigo sobre SQL HAVING vs. WHERE.

Cenário V: ONDE e HAVING com JOINs

O exemplo a seguir leva um passo adiante para usar um JOIN com WHERE e HAVING. Ele junta os dados de duas tabelas baseadas em uma coluna comum, employee_id. As cláusulas WHERE e HAVING seguem a ordem de execução que acabamos de discutir.

SELECT e.job_id, edv.location_id, SUM(e.salary)
FROM hr.employees e
JOIN hr.emp_details_view edv
ON e.employee_id=edv.employee_id
WHERE e.job_id IN ('IT_PROG', 'SA_MAN')
GROUP BY e.job_id, edv.location_id
HAVING SUM(e.salary) > 5000
ORDER BY e.job_id; 
JOB_IDLOCATION_IDSUM(E.SALARY)
IT_PROG140013800
SA_MAN250025000

Este exemplo seleciona a coluna job_id da tabela hr.employeea coluna location_id da tabela hr.emp_details_viewe o total de salários para cada combinação de job_id e location_id. A condição para unir as tabelas está listada no operador ON. Esta condição é baseada na coluna comum, employee_id.

Em seguida, a cláusula WHERE filtra os registros apenas para job_ids que são IT_PROG ou SA_MAN. A cláusula GROUP BY agrupa os registros através da combinação das colunas job_id e location_id. Finalmente, a cláusula HAVING filtra o valor agregado SUM(e.salary) para aqueles maiores que 5000.

A cláusula ORDER BY ordena os registros de saída (em ordem ascendente por padrão) pela coluna job_id. Para mais discussões sobre as cláusulas GROUP BY e ORDER BY, visite o artigo sobre GROUP BY vs. ORDER BY.

Diferença entre as cláusulas WHERE e HAVING em SQL

Aqui está um resumo das diferenças entre as cláusulas de WHERE e HAVING em SQL:

WHERE clauseHAVING clause
FilteringFilters individual rows fetched by SELECT, i.e., the output of the SELECT commandFilters groups of rows created by GROUP BY, i.e., the output of the GROUP BY clause
ConditionsCannot have conditions containing aggregate functionsFocuses on conditions containing aggregate functions
SyntaxWHERE comes before GROUP BY in the syntaxHAVING comes after GROUP BY in the syntax
Order of evaluationWHERE clause is evaluated before GROUP BY in the process flow, before aggregation is performedHAVING clause is evaluated after GROUP BY in the process flow, after aggregation is performed
With/without GROUP BYCan be used with or without GROUP BY, since WHERE and GROUP BY are not relatedShould be used with GROUP BY; otherwise, the output of SELECT is treated as one group

WHERE e HAVING são uma grande parte do aprendizado de SQL. Confira o SQL para Iniciantes curso para ajudar a desenvolver suas habilidades SQL.