SQL: tener VS donde


202

Tengo las siguientes dos tablas:

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

Quiero encontrar al profesor con la mayor especialización. Cuando intento esto, no funciona:

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);

Pero cuando intento esto, 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); 

¿Cuál es la razón? Gracias.


2
¿Puede aclarar qué versión de SQL está utilizando (MySQL, MS SQL, PostgreSQL, Oracle, etc.)? Además, cuando dice "no funciona", ¿quiere decir que los resultados no son los esperados o que hay un error de compilación / análisis?
jklemmack

2
¿Por qué usas ALL en lugar de MAX? ¿Hay alguna ventaja?
skan

Respuestas:


352

WHERELa cláusula introduce una condición en filas individuales ; HAVINGLa cláusula introduce una condición en las agregaciones , es decir, los resultados de la selección en los que se ha producido un único resultado, como conteo, promedio, mínimo, máximo o suma, a partir de varias filas. Su consulta requiere un segundo tipo de condición (es decir, una condición en una agregación) por lo tantoHAVING funciona correctamente.

Como regla general, use WHEREantes GROUP BYy HAVINGdespuésGROUP BY . Es una regla bastante primitiva, pero es útil en más del 90% de los casos.

Mientras lo hace, es posible que desee volver a escribir su consulta utilizando la versión ANSI de la unión:

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)

Esto eliminaría WHEREque se usara como una condición de unión theta .


40

HAVINGopera en agregados. Como COUNTes una función agregada, no puede usarla en una WHEREcláusula.

Aquí hay algunas lecturas de MSDN sobre funciones agregadas.


30

Primero debemos conocer el orden de ejecución de las Cláusulas, es decir, DE> DÓNDE> AGRUPAR POR> TENER> DISTINTO> SELECCIONAR> ORDENAR POR. Dado que la Cláusula WHERE se ejecuta antes de la Cláusula GROUP BY, los registros no se pueden filtrar aplicando WHERE a los registros aplicados por GROUP BY .

"TENER es igual que la cláusula WHERE pero se aplica en registros agrupados".

primero la cláusula WHERE recupera los registros según la condición, luego la cláusula GROUP BY los agrupa en consecuencia y luego la cláusula HAVING recupera los registros del grupo según la condición de tener.


¿Se usa siempre este orden de operaciones? ¿Qué sucede si el optimizador de consultas cambia el orden?
MSIS

1
@MSIS incluso si el optimizador de consultas cambia el orden, el resultado debería ser el mismo que si se siguiera este orden. Es un orden lógico.
Stephen

18
  1. La cláusula WHERE se puede usar con las instrucciones SELECT, INSERT y UPDATE, mientras que HAVING solo se puede usar con la declaración SELECT.

  2. WHERE filtra las filas antes de la agregación (GROUP BY), mientras que TENIENDO grupos de filtros después de las agregaciones.

  3. La función de agregado no se puede usar en la cláusula WHERE a menos que esté en una subconsulta contenida en la cláusula HAVING, mientras que las funciones de agregado se pueden usar en la cláusula HAVING.

Fuente


11

No vi un ejemplo de ambos en una consulta. Entonces este ejemplo podría ayudar.

  /**
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

Esto filtra la tabla primero por el Id. De la compañía, luego la agrupa (por país y ciudad) y, además, la filtra a las agregaciones de ciudades de México. El ID de compañía no era necesario en la agregación, pero pudimos usar DÓNDE para filtrar solo las filas que queríamos antes de usar GROUP BY.


no es un buen ejemplo, ya que podría convertir: `WHERE companyId = 884501253109 GROUP BY country, city HAVING country = 'MX' 'a:` WHERE companyId = 884501253109, country =' MX 'GROUP BY city `
Etienne Herlaut

Si solo mueve el filtro [country] al WHERE que ha sugerido, la consulta generaría un error de SELECT [country], ya que [country] ya no se incluye en la agregación GROUP BY, por lo que no se puede seleccionar.
Nhan

Su punto de optimización se toma al mover [país] al DONDE ya que eso sería un conjunto de datos más pequeño a GROUP BY con posterioridad. Por supuesto, esto es solo un ejemplo para ilustrar los posibles usos. Podemos cambiar a TENER suma (total)> 1000 y ese sería un caso completamente válido para incluir DONDE y TENER.
Nhan

9

No puede usar la cláusula where con funciones agregadas porque donde fetch registra en función de la condición, entra en la tabla registro por registro y luego recupera el registro en función de la condición que tenemos. Así que esa vez no podemos dónde cláusula. Si bien tener cláusula funciona en el conjunto de resultados que finalmente obtenemos después de ejecutar una consulta.

Consulta de ejemplo:

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

Esto almacenará el resultSet en una memoria temporal, luego tener una cláusula realizará su trabajo. Entonces podemos usar fácilmente funciones agregadas aquí.


2
Creo que no podemos usar la cláusula HAVING sin la cláusula GROUP BY. Posición de la cláusula HAVING - SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY
Morez

4

1. Podemos usar la función de agregado con la cláusula HAVING no mediante la cláusula WHERE, por ejemplo, min, max, avg.

2. La cláusula WHERE elimina la tupla de registro por tupla La cláusula HAVING elimina todo el grupo de la colección de grupos

La mayoría de las veces HAVING se usa cuando tiene grupos de datos y WHERE se usa cuando tiene datos en filas.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.