SQL - tendo VS em que


202

Eu tenho as seguintes duas tabelas:

1. Lecturers (LectID, Fname, Lname, degree).
2. Lecturers_Specialization (LectID, Expertise).

Quero encontrar o professor com mais Especialização. Quando tento isso, ele não está funcionando:

SELECT
  L.LectID, 
  Fname, 
  Lname 
FROM Lecturers L, 
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
AND COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID);

Mas quando eu tento isso, funciona:

SELECT
  L.LectID,
  Fname,
  Lname 
FROM Lecturers L,
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
GROUP BY L.LectID,
         Fname,
         Lname 
HAVING COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID); 

Qual é a razão? Obrigado.


2
Você pode esclarecer qual versão do SQL você está usando (MySQL, MS SQL, PostgreSQL, Oracle, etc.). Além disso, quando você diz "não está funcionando", você quer dizer que os resultados não estão como o esperado ou que há um erro de compilação / análise?
Jklemmack

2
Por que você usa ALL em vez de MAX ?. Existe alguma vantagem?
skan

Respostas:


352

WHEREA cláusula introduz uma condição em linhas individuais ; HAVINGA cláusula introduz uma condição nas agregações , ou seja, resultados da seleção em que um único resultado, como contagem, média, min, máximo ou soma, foi produzido a partir de várias linhas. Sua consulta solicita um segundo tipo de condição (ou seja, uma condição em uma agregação), portanto, HAVINGfunciona corretamente.

Como regra geral, use WHEREantes GROUP BYe HAVINGdepoisGROUP BY . É uma regra bastante primitiva, mas é útil em mais de 90% dos casos.

Enquanto você está nisso, você pode reescrever sua consulta usando a versão ANSI da associação:

SELECT  L.LectID, Fname, Lname
FROM Lecturers L
JOIN Lecturers_Specialization S ON L.LectID=S.LectID
GROUP BY L.LectID, Fname, Lname
HAVING COUNT(S.Expertise)>=ALL
(SELECT COUNT(Expertise) FROM Lecturers_Specialization GROUP BY LectID)

Isso eliminaria o WHEREque foi usado como uma condição de junção teta .


40

HAVINGopera em agregados. Como COUNTé uma função agregada, você não pode usá-la em uma WHEREcláusula.

Aqui estão algumas leituras do MSDN sobre funções agregadas.


30

Primeiro, devemos saber a ordem de execução das Cláusulas, ou seja, DE> ONDE> GRUPO POR> TER> DISTINTO> SELECIONAR> ORDENAR POR. Como a cláusula WHERE é executada antes da cláusula GROUP BY, os registros não podem ser filtrados aplicando WHERE a um registro aplicado GROUP BY .

"HAVING é o mesmo que a cláusula WHERE, mas é aplicada em registros agrupados".

primeiro, a cláusula WHERE busca os registros com base na condição, depois a cláusula GROUP BY os agrupa de acordo e, em seguida, a cláusula HAVING busca os registros do grupo com base na condição tendo.


Essa ordem de operações é sempre usada? E se o otimizador de consulta alterar a ordem?
MSIS

1
@MSIS, mesmo que o otimizador de consulta altere a ordem, o resultado deve ser o mesmo que se essa ordem fosse seguida. É uma ordem lógica.
Stephen

18
  1. A cláusula WHERE pode ser usada com as instruções SELECT, INSERT e UPDATE, enquanto HAVING pode ser usada apenas com a instrução SELECT.

  2. WHERE filtra linhas antes da agregação (GROUP BY), enquanto HAVING filtra grupos após a agregação.

  3. A função agregada não pode ser usada na cláusula WHERE, a menos que esteja em uma subconsulta contida na cláusula HAVING, enquanto as funções agregadas podem ser usadas na cláusula HAVING.

Fonte


11

Não viu um exemplo dos dois em uma consulta. Portanto, este exemplo pode ajudar.

  /**
INTERNATIONAL_ORDERS - table of orders by company by location by day
companyId, country, city, total, date
**/

SELECT country, city, sum(total) totalCityOrders 
FROM INTERNATIONAL_ORDERS with (nolock)
WHERE companyId = 884501253109
GROUP BY country, city
HAVING country = 'MX'
ORDER BY sum(total) DESC

Isso filtra a tabela primeiro pelo companyId, depois a agrupa (por país e cidade) e, adicionalmente, filtra-a apenas para agregações de cidades do México. O companyId não era necessário na agregação, mas pudemos usar WHERE para filtrar apenas as linhas que desejávamos antes de usar GROUP BY.


não é um bom exemplo como você pode converter: `WHERE companyId = 884501253109 GRUPO POR país, cidade HAVING country = 'MX' 'para:` WHERE companyId = 884501253109, country =' MX 'GROUP BY city `
Etienne Herlaut

Se apenas mover o filtro [country] para WHERE você sugeriu, a consulta apresentaria um erro em SELECT [country], pois [country] não está mais incluído na agregação GROUP BY, portanto, não pode ser selecionado.
Nhan

Seu ponto de vista da otimização é levado ao mover [país] para WHERE, pois isso seria um conjunto de dados menor para GROUP BY com mais tarde. Claro que este é apenas um exemplo para ilustrar possíveis usos. Podemos mudar para HAVING soma (total)> 1000 e esse seria um caso completamente válido para incluir WHERE e HAVING.
Nhan

9

Você não pode usar a cláusula where com funções agregadas porque, onde busca registros com base na condição, ela entra na tabela registro por registro e, em seguida, busca o registro com base na condição que fornecemos. Então, dessa vez, não podemos cláusula where. Enquanto ter cláusula trabalha no resultSet que finalmente obtemos após executar uma consulta.

Consulta de exemplo:

select empName, sum(Bonus) 
from employees 
order by empName 
having sum(Bonus) > 5000;

Isso armazenará o resultSet em uma memória temporária, e a cláusula having fará seu trabalho. Portanto, podemos usar facilmente funções agregadas aqui.


2
Acho que não podemos usar a cláusula HAVING sem a cláusula GROUP BY. Posição da cláusula HAVING - SELECT -> FROM -> ONDE -> GRUPO POR -> TENDO -> ORDENAR POR
Morez

4

1. Podemos usar a função agregada com a cláusula HAVING e não pela cláusula WHERE, por exemplo, min, max, avg.

2. A cláusula WHERE elimina a tupla de registro pela tupla A cláusula HAVING elimina todo o grupo da coleção de grupos

HAVING é usado principalmente quando você tem grupos de dados e WHERE é usado quando você tem dados em linhas.

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.