12th Dec 2022 11 minutos de leitura Qual é a diferença entre as cláusulas WHERE e HAVING em SQL? Martyna Sławińska sql aprender sql group by Índice Fluxo de Processo Lógico para Consultas com WHERE e HAVING Em primeiro lugar, o Essencial: Especificação das condições em WHERE e HAVING Exemplos Cenário I: A cláusula WHERE Cenário II: A Cláusula HAVING Cenário III: A Cláusula GROUP BY ONDE COM UM GROUP BY Cláusula tendo um grupo de acordo com uma cláusula Cenário IV: Usando as duas cláusulas WHERE e HAVING em conjunto Cenário V: ONDE e HAVING com JOINs 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. Figura 1: Ordem de execução nas consultas SQL. 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. 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. 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). A seguir é a cláusula HAVING, que filtra os grupos criados em GROUP BY em vez de registros individuais. 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. 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: A cláusula WHERE primeiro filtra os registros com manager_id que não são encontrados na lista que segue o operador IN. 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: SELECT: seleciona as colunas do banco de dados a serem produzidas para o resultado. FROM: lista as tabelas a serem usadas na consulta. WHERE: filtra os registros individuais. GROUP BY: agrupa os registros com base na(s) coluna(s) especificada(s). HAVING: filtra os grupos definidos por GROUP BY. 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. Tags: sql aprender sql group by