5th Dec 2022 Lectura de 12 minutos ¿Cuál es la diferencia entre las cláusulas WHERE y HAVING en SQL? Martyna Sławińska SQL aprender SQL agrupar por Índice Flujo de Proceso Lógico para Consultas con WHERE y HAVING Primero, lo esencial: Especificación de condiciones en WHERE y HAVING Ejemplos Escenario I: La cláusula WHERE Escenario II: La cláusula HAVING Escenario III: La cláusula GROUP BY WHERE con una cláusula GROUP BY HAVING con una cláusula GROUP BY Escenario IV: Uso conjunto de las cláusulas WHERE y HAVING Escenario V: WHERE y HAVING con JOINs Diferencia entre las cláusulas WHERE y HAVING en SQL A medida que la cantidad de datos en el mundo crece día a día, aumenta la necesidad de gestionar y consultar los datos de manera eficiente. SQL ofrece formas de manipular y consultar datos a cualquier escala. Como parte importante de esto, las cláusulas WHERE y HAVING permiten filtrar los datos según las necesidades, pero no son lo mismo. Explicaremos en detalle las diferencias entre ellas. Una de las tareas más comunes en la manipulación y consulta de datos es el filtrado mediante las cláusulas WHERE y HAVING. Aunque ambas filtran datos basándose en condiciones y/o funciones definidas por el usuario, existen importantes diferencias en la forma en que se ejecuta cada cláusula. Este artículo explica en detalle cuándo usar WHERE o HAVING. Explicaremos brevemente el flujo de proceso lógico de una consulta SQL que incluya las cláusulas WHERE y/o HAVING, seguido de algunos escenarios de práctica y ejemplos para que los resolvamos juntos. Flujo de Proceso Lógico para Consultas con WHERE y HAVING El orden en que se escribe una consulta SQL difiere del orden de ejecución. Veamos lo siguiente como ejemplo: 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; El flujo de proceso lógico de una consulta SQL está diagramado a continuación. Figura 1: Orden de ejecución de las consultas SQL. El proceso lógico de una consulta SQL comienza con una sentencia FROM, que recoge los datos de las tablas enumeradas en la consulta. También puede contener una cláusula JOIN que combina dos o más tablas utilizando el operador ON. Tenga en cuenta que las condiciones utilizadas en la cláusula WHERE también pueden utilizarse en el operador ON de la cláusula JOIN. Asimismo, las tablas combinadas mediante condiciones en el operador ON de la cláusula JOIN pueden utilizarse en la cláusula WHERE. Sin embargo, se debe utilizar WHERE sólo para las condiciones que filtran filas individuales. Esto mejora la legibilidad de la consulta y permite que el operador ON maneje sólo la combinación de las tablas, que es su propósito. El siguiente paso en el flujo del proceso lógico es la cláusula WHERE, que filtra los registros a los que cumplen la(s) condición(es) y/o la(s) función(es) definida(s) por el usuario y los pasa. A la cláusula WHERE le sigue la cláusula GROUP BY, que agrupa los registros recibidos de la condición WHERE. Por ejemplo, la(s) columna(s) listada(s) en la cláusula GROUP BY puede(n) ser los equipos, y otras columnas son agregadas por la(s) función(es) de agregación y asignadas a los grupos/equipos correspondientes. A continuación está la cláusula HAVING, que filtra los grupos creados en GROUP BY en lugar de los registros individuales. En este punto, el procesamiento lógico pasa al comando SELECT. Evalúa qué columnas van a ser enviadas a la salida. También evalúa cualquier palabra clave como UNIQUE, DISTINCT, y TOP, si se incluye. La cláusula ORDER BY se ejecuta al final del flujo del proceso lógico. Ordena los datos por la(s) columna(s) especificada(s) en ella y en orden ascendente por defecto. Primero, lo esencial: Especificación de condiciones en WHERE y HAVING Existe una amplia gama de operadores que nos ayudan a crear y combinar condiciones en las cláusulas WHERE y HAVING: signos de comparación: <, >, <=, >=, =, <> comprobación de valores nulos: IS NULL, IS NOT NULL comodines: LIKE, '%=_' comprobación de rangos: BETWEEN comprobación de la presencia en un conjunto: IN prueba de existencia: EXISTS signos de comparación cuantificados: ALL, ANY, SOME combinación lógica de las condiciones: AND, OR, NOT Los operandos de una cláusula WHERE pueden incluir las columnas enumeradas en SELECT, excepto las columnas utilizadas en las funciones de agregación. En cambio, HAVING filtra por valores resultantes de la función de agregación como SUM(), COUNT(), y AVG(), entre otros. Ejemplos Las tablas employee y emp_details_view, que se muestran parcialmente a continuación, se utilizan a lo largo de los próximos ejemplos. 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 Escenario I: La cláusula WHERE La cláusula WHERE se utiliza para filtrar filas individuales de datos obtenidos de la base de datos mediante SELECT. Los registros que no cumplen la(s) condición(es) de WHERE no se incluyen en la salida. Veamos un ejemplo: where age > 25 AND city='New York' Se pasan sólo los registros cuya edad es superior a 25 años y cuya city es Nueva York. En la sintaxis de la consulta, la cláusula WHERE se utiliza directamente después de SELECT y FROM. Filtra las filas individuales -los registros sin agrupar- obtenidas por la consulta, para determinar qué registros deben pasarse a la cláusula GROUP BY. Examinemos el resultado de la siguiente consulta que utiliza la 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 En el ejemplo anterior se obtienen las columnas last_name, hire_date, y manager_id de la tabla hr.employee. La cláusula WHERE filtra la salida como sigue: last_name debe incluir una letra "a"; hire_date debe ser mayor o igual que el 01-ENE-05 y menor o igual que el 01-ENE-07; y manager_id debe tener un valor y no ser nulo. Sólo se presentan en la salida los registros que cumplen las condiciones de WHERE. Veamos otro ejemplo del mismo escenario: 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 ejemplo da salida a las columnas employee_id, salary, y job_id de la tabla hr.employee. La cláusula WHERE filtra la salida como sigue: salary debe ser inferior a 3000, o debe ser igual a 9000; y job_id debe ser igual a cualquier valor indicado en el operador IN. Al igual que en la consulta anterior, la salida sólo contiene los registros que cumplen la condición WHERE. Tenga en cuenta que WHERE no puede contener condiciones que incluyan funciones de agregación. Ese es el trabajo para HAVING. Escenario II: La cláusula HAVING HAVING se utiliza para filtrar grupos de registros creados por la cláusula GROUP BY. Por esta razón, la cláusula HAVING debe seguir a la cláusula GROUP BY. Es similar a la cláusula WHERE que filtra la salida de SELECT, sólo que WHERE filtra registros individuales mientras que HAVING filtra grupos. Las funciones agregadas como SUM(), MAX(), MIN(), AVG() y COUNT() son el objetivo de la cláusula HAVING. Veámoslo en acción en los ejemplos. 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 El ejemplo anterior enumera los departamentos junto con la suma de todos los salarios de cada departamento. Sólo los department_idcuyos salarios totales son superiores a 10000 aparecen en la lista. Los que no cumplen la condición establecida por la cláusula HAVING se filtran. Veamos otro ejemplo: 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 el número de empleados para cada combinación de job_id y salario. La cláusula WHERE filtra los registros a los que tienen sueldos superiores a 12000. La cláusula GROUP BY, que sigue a WHERE, especifica la agrupación por columnas no agregadas job_id y salary. Por último, la cláusula HAVING especifica que el valor agregado COUNT(employee_id) debe ser inferior a 10. Escenario III: La cláusula GROUP BY WHERE con una cláusula GROUP BY La cláusula WHERE debe colocarse siempre antes de GROUP BY. Esto se debe a que WHERE filtra filas individuales de datos, no grupos de filas. La cláusula GROUP BY toma las filas individuales del resultado del filtro a nivel de fila WHERE para crear grupos de filas. He aquí un ejemplo: 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 La consulta anterior se evalúa de la siguiente manera: La cláusula WHERE filtra primero los registros con manager_id que no se encuentran en la lista que sigue al operador IN. A continuación, la cláusula GROUP BY agrupa por job_id los registros que han superado la condición WHERE. La consulta calcula el total de los salarios de los empleados gestionados por cada uno de los responsables especificados (manager_ids 100, 101, 102, 103). Los salarios de los empleados que dependen de otros gerentes no se incluyen en el cálculo de este total. HAVING con una cláusula GROUP BY La cláusula GROUP BY se utiliza a menudo con las funciones de agregación. Crea valores de resumen para las columnas enumeradas en GROUP BY. En cambio, HAVING siempre sigue a una cláusula GROUP BY, ya que HAVING trabaja con los grupos creados por GROUP BY. Consideremos un caso de uso de HAVING en el que no se puede omitir la cláusula GROUP BY. Esto es así si hay columnas listadas en SELECT que no son utilizadas por las funciones de agregación, como department_id en el ejemplo siguiente. Estas columnas no agregadas deben figurar en GROUP BY para agrupar los datos. 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 Sin embargo, HAVING puede utilizarse sin acompañar a GROUP BY. Tenga en cuenta que en este caso, HAVING se aplica a toda la salida de SELECT, tratándola como un único grupo. El siguiente es un ejemplo: SELECT round(avg(salary)) FROM hr.emp_details_view HAVING avg(salary) < 11000; ROUND(AVG(SALARY)) 10056 La consulta devuelve un único valor que contiene la media de todos los salarios. Observe que la cláusula HAVING pone un límite a este valor agregado. Si la media calculada fuera superior a 11000, la consulta no habría devuelto ningún registro. El siguiente es un ejemplo de pseudoagregación, en el que se utilizan funciones de agregación en lugar de 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 La función MIN() se utiliza aquí en las columnas first_name y department_id. No se llama en un uso típico de las funciones de agregación, sino con el propósito de evitar un GROUP BY. En este caso, la salida es un solo registro de datos que consiste en el valor mínimo de first_name, el valor mínimo de department_id, y el valor máximo de salario, cada uno de la tabla completa. Tenga en cuenta que estos 3 valores pueden provenir de 3 registros diferentes como ocurre en este ejemplo. Además, en este caso, si el salario mínimo de toda la tabla fuera 1000 o menos, la consulta no devolvería ningún registro. Este ejemplo concreto es un poco artificial para poder mostrar algo más sencillo. Aunque es menos común que GROUP BY, la pseudoagregación puede utilizarse en consultas que tratan todas las filas incluidas como un solo grupo. El uso de HAVING con o sin GROUP BY puede variar según la base de datos. Si desea obtener más información sobre la cláusula GROUP BY, visite el artículo Cláusula GROUP BY. Escenario IV: Uso conjunto de las cláusulas WHERE y HAVING La sintaxis para utilizar WHERE y HAVING en una consulta sigue el orden específico que se presenta a continuación: SELECT: selecciona las columnas de la base de datos que se enviarán al resultado. FROM: enumera las tablas que se utilizarán en la consulta. WHEREFiltra los registros individuales. GROUP BYagrupa los registros en función de la(s) columna(s) especificada(s). HAVINGfiltra los grupos definidos por GROUP BY. ORDER BY: ordena los registros de salida por la(s) columna(s) especificada(s). Veamos un ejemplo que utiliza todo lo anterior. 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 La consulta obtiene el mínimo salary y el máximo salary para cada combinación de city y country_id, esta última limitada a EE.UU. y Reino Unido sólo por la condición WHERE. Supongamos que tiene 10 registros con EE.UU. como country_id, y dentro de ellos, hay 5 registros con Nueva York como ciudad y otros 5 con Los Ángeles como ciudad. Al ejecutar la consulta anterior, estos 10 registros se convierten en 2 registros un registro para EE.UU. y Nueva York, con sus salarios mínimos y máximos, otro registro para EE.UU. y Los Ángeles, también con sus salarios mínimos y máximos. Para más información sobre las diferencias entre WHERE y HAVING, visite el artículo sobre SQL HAVING vs. WHERE. Escenario V: WHERE y HAVING con JOINs El siguiente ejemplo da un paso más para utilizar un JOIN con WHERE y HAVING. Une los datos de dos tablas basándose en una columna común, employee_id. Las cláusulas WHERE y HAVING siguen el orden de ejecución que acabamos de comentar. 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 ejemplo selecciona la columna job_id de la tabla hr.employeela columna location_id de la tabla hr.emp_details_viewy el total de los salarios para cada combinación de job_id y location_id. La condición para unir las tablas aparece en el operador ON. Esta condición se basa en la columna común, employee_id. A continuación, la cláusula WHERE filtra los registros a sólo job_ids que sean IT_PROG o SA_MAN. La cláusula GROUP BY agrupa los registros por la combinación de las columnas job_id y location_id. Por último, la cláusula HAVING filtra el valor agregado SUM(e.salary) a los mayores de 5000. La cláusula ORDER BY ordena los registros de salida (en orden ascendente por defecto) por la columna job_id. Para más información sobre las cláusulas GROUP BY y ORDER BY, visite el artículo sobre GROUP BY vs. ORDER BY. Diferencia entre las cláusulas WHERE y HAVING en SQL Aquí hay un resumen a simple vista de las diferencias entre las cláusulas WHERE y HAVING en 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 y HAVING son una gran parte del aprendizaje de SQL. Consulte el SQL para principiantes curso para ayudarte a desarrollar tus habilidades en SQL. Tags: SQL aprender SQL agrupar por