Capítulo 4. Conceptos básicos de consulta
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com
Una consulta es un apodo para una sentencia SELECT
, que consta de seis cláusulas principales. Cada sección de este capítulo cubre una cláusula en detalle:
La última sección de este capítulo trata de la cláusula LIMIT, que admiten MySQL, PostgreSQL y SQLite.
Los ejemplos de código de este capítulo hacen referencia a cuatro tablas:
waterfall
-
Cascadas en la Alta Península de Michigan
owner
-
propietarios de las cascadas
county
-
comarcas donde se encuentran las cascadas
tour
-
recorridos que consisten en múltiples paradas en cascadas
Aquí tienes un ejemplo de consulta que utiliza las seis cláusulas principales. Le siguen los resultados de la consulta, que también se conocen comoconjunto de resultados.
-- Tours with 2 or more public waterfalls SELECT t.name AS tour_name, COUNT(*) AS num_waterfalls FROM tour t LEFT JOIN waterfall w ON t.stop = w.id WHERE w.open_to_public = 'y' GROUP BY t.name HAVING COUNT(*) >= 2 ORDER BY tour_name; tour_name num_waterfalls ---------- --------------- M-28 6 Munising 6 US-2 4
Consultar una base de datos significa recuperar datos de una base de datos, normalmente de una tabla o varias tablas.
Nota
También es posible consultar una vista en lugar de una tabla. Las vistas se parecen a las tablas y derivan de ellas, pero no contienen datos. Encontrarás más información sobre las vistas en "Vistas", en el Capítulo 5.
La cláusula SELECT
La cláusula SELECT
especifica en las columnas que quieres que devuelva una sentencia.
En la cláusula SELECT
, la palabra clave SELECT
va seguida de una lista de nombres de columnas y/o expresiones separadas por comas. Cada nombre de columna y/o expresión se convierte entonces en una columna de los resultados.
Seleccionar columnas
La cláusula SELECT
más sencilla enumera uno o varios nombres de columnas de las tablas de la cláusula FROM
:
SELECT id, name FROM owner; id name ----- ---------------- 1 Pictured Rocks 2 Michigan Nature 3 AF LLC 4 MI DNR 5 Horseshoe Falls
Seleccionar todas las columnas
Para devolver todas las columnas de una tabla, puedes utilizar un único asterisco en lugar de escribir el nombre de cada columna:
SELECT * FROM owner; id name phone type ----- ---------------- ------------- -------- 1 Pictured Rocks 906.387.2607 public 2 Michigan Nature 517.655.5655 private 3 AF LLC private 4 MI DNR 906.228.6561 public 5 Horseshoe Falls 906.387.2635 private
Advertencia
El asterisco es un atajo útil cuando pruebas consultas porque puede ahorrarte bastante tecleo. Sin embargo, es arriesgado utilizar el asterisco en código de producción porque las columnas de una tabla pueden cambiar con el tiempo, haciendo que tu código falle cuando haya menos o más columnas de las esperadas.
Seleccionar expresiones
Además de enumerar simplemente columnas, también puedes enumerar expresiones más complejas dentro de la cláusula SELECT
para que aparezcan como columnas en los resultados.
El enunciado siguiente incluye una expresión para calcular un descenso del 10% de la población, redondeado a cero decimales:
SELECT name, ROUND(population * 0.9, 0) FROM county; name ROUND(population * 0.9, 0) ---------- --------------------------- Alger 8876 Baraga 7871 Ontonagon 7036 ...
Seleccionar funciones
Las expresiones de la lista SELECT
suelen hacer referencia a columnas de las tablas de las que estás extrayendo información, pero hay excepciones. Por ejemplo, una función habitual que no hace referencia a ninguna tabla es la que devuelve la fecha actual:
SELECT CURRENT_DATE; CURRENT_DATE ------------- 2021-12-01
El código anterior funciona en MySQL, PostgreSQL y SQLite. El código equivalente que funciona en otros RDBMS se puede encontrar en "Funciones Datetime" en el Capítulo 7.
Nota
La mayoría de las consultas incluyen tanto una cláusula SELECT
como una FROM
, pero sólo se requiere la cláusula SELECT
cuando se utilizan funciones concretas de la base de datos, como CURRENT_DATE
.
También es posible incluir expresiones dentro de la cláusula SELECT
que sean subconsultas (una consulta anidada dentro de otra consulta). Encontrarás más detalles en "Selección de subconsultas".
Aliasing Columnas
El objetivo de un alias de columna es dar un nombre temporal a cualquier columna o expresión que aparezca en la cláusula SELECT
. Ese nombre temporal, o alias de columna, se muestra después como nombre de columna en los resultados.
Ten en cuenta que no se trata de un cambio de nombre permanente, ya que los nombres de las columnas de las tablas originales permanecen inalterados. El alias sólo existe dentro de la consulta.
Este código muestra tres columnas.
SELECT id, name, ROUND(population * 0.9, 0) FROM county; id name ROUND(population * 0.9, 0) ----- ---------- --------------------------- 2 Alger 8876 6 Baraga 7871 7 Ontonagon 7036 ...
Supongamos que queremos cambiar el nombre de las columnas de los resultados. id
es demasiado ambigua y nos gustaría darle un nombre más descriptivo. ROUND(population * 0.9, 0)
es demasiado larga y nos gustaría darle un nombre más sencillo.
Para crear un alias de columna, sigue el nombre de una columna o expresión con (1) un nombre de alias o (2) la palabra clave AS
y un nombre de alias.
-- alias_name SELECT id county_id, name, ROUND(population * 0.9, 0) estimated_pop FROM county;
o:
-- AS alias_name SELECT id AS county_id, name, ROUND(population * 0.90, 0) AS estimated_pop FROM county; county_id name estimated_pop ---------- ---------- -------------- 2 Alger 8876 6 Baraga 7871 7 Ontonagon 7036 ...
Ambas opciones se utilizan en la práctica al crear alias. Dentro de la cláusula SELECT
, la segunda opción es más popular porque la palabra clave AS
facilita visualmente la diferenciación de nombres de columnas y alias entre una larga lista de nombres de columnas.
Nota
Las versiones antiguas de PostgreSQL requieren el uso de AS
al crear un alias de columna.
Aunque los alias de columna no son obligatorios, son muy recomendables cuando se trabaja con expresiones para dar nombres sensatos a las columnas de los resultados.
Alias con distinción entre mayúsculas y minúsculas y puntuación
Como puedes ver con los alias de columna county_id
yestimated_pop
la convención es utilizar letras minúsculas con guiones bajos en lugar de espacios al nombrar los alias de columna.
También puedes crear alias que contengan letras mayúsculas, espacios y signos de puntuación utilizando la sintaxis de comillas dobles, como se muestra en este ejemplo:
SELECT id AS "Waterfall #", name AS "Waterfall Name" FROM waterfall; Waterfall # Waterfall Name ------------ --------------- 1 Munising Falls 2 Tannery Falls 3 Alger Falls ...
Columnas de calificación
Supongamos que escribes una consulta que extrae datos de dos tablas y ambas contienen una columna llamada name
. Si sólo incluyeras name
en la cláusula SELECT
, el código no sabría a qué tabla te estás refiriendo.
Para resolver este problema, puedes calificar el nombre de una columna por su nombre de tabla. En otras palabras, puedes dar a una columna un prefijo para especificar a qué tabla pertenece utilizando la notación por puntos, como en table_name.column_name
.
El siguiente ejemplo consulta una única tabla, por lo que, aunque no es necesario calificar las columnas aquí, se muestra amodo de demostración. Así es como calificarías una columna por su nombre de tabla:
SELECT owner.id, owner.name FROM owner;
Consejo
Si obtienes un error en SQL haciendo referencia a un nombre de columna ambiguo, significa que varias tablas de tu consulta tienen una columna con el mismo nombre y no has especificado a qué combinación de tabla/columna te refieres. Puedes resolver el error calificando el nombre de la columna.
Tablas de clasificación
Si calificas un nombre de columna por su nombre de tabla, también puedes calificar ese nombre de tabla por su nombre de base de datos o esquema. La siguiente consulta recupera datos específicamente de la tabla dentro del esquema : owner
sqlbook
SELECT sqlbook.owner.id, sqlbook.owner.name FROM sqlbook.owner;
El código anterior es largo, ya que sqlbook.owner
se repite varias veces. Para ahorrar tecleo, puedes proporcionar un alias de tabla. El siguiente ejemplo da el alias o
a la tabla owner
:
SELECT o.id, o.name FROM sqlbook.owner o;
o:
SELECT o.id, o.name FROM owner o;
Seleccionar subconsultas
Una subconsulta es una consulta anidada dentro de otra consulta. Las subconsultas pueden estar dentro de varias cláusulas, incluida la cláusula SELECT
.
En el siguiente ejemplo, además de id
, name
, y population
, digamos que también queremos ver la población media de todos los condados. Al incluir una subconsulta, estamos creando una nueva columna en los resultados para la población media.
SELECT id, name, population, (SELECT AVG(population) FROM county) AS average_pop FROM county; id name population average_pop ----- ---------- ----------- ------------ 2 Alger 9862 18298 6 Baraga 8746 18298 7 Ontonagon 7818 18298 ...
Hay que tener en cuenta algunas cosas:
-
Cuando escribas una subconsulta dentro de la cláusula
SELECT
, es muy recomendable que especifiques un alias de columna, que en este caso fueaverage_pop
. De ese modo, la columna tendrá un nombre sencillo en los resultados. -
Sólo hay un valor en la columna
average_pop
que se repite en todas las filas. Al incluir una subconsulta dentro de la cláusulaSELECT
, el resultado de la subconsulta debe devolver una única columna y cero o una fila, como se muestra en la siguiente subconsulta para calcular lapoblación media.
SELECT AVG(population) FROM county; AVG(population) ---------------- 18298
-
Si la subconsulta devolvía cero filas, la nueva columna se rellenaría con los valores de
NULL
.
DISTINTO
Cuando se incluye una columna en la cláusula SELECT
, por defecto se devuelven todas las filas. Para ser más explícito, puedes incluir la palabra clave ALL
, pero es puramente opcional. Las siguientes consultas devuelven cada combinación type
/open_to_public
.
SELECT o.type, w.open_to_public FROM owner o JOIN waterfall w ON o.id = w.owner_id;
o:
SELECT ALL o.type, w.open_to_public FROM owner o JOIN waterfall w ON o.id = w.owner_id; type open_to_public -------- --------------- public y public y public y private y private y private y private y public y
Si quieres eliminar las filas duplicadas de los resultados, puedes utilizar la palabra clave DISTINCT
. La siguiente consulta devuelve una lista de combinaciones únicas type
/open_to_public
.
SELECT DISTINCT o.type, w.open_to_public FROM owner o JOIN waterfall w ON o.id = w.owner_id; type open_to_public -------- --------------- public y private y
CONTAR y DISTINTO
Para contar el número de valores únicos dentro de una sola columna, puedes combinar las palabras clave COUNT
y DISTINCT
dentro de la cláusula SELECT
. La siguiente consulta devuelve el número de valores únicos type
.
SELECT COUNT(DISTINCT type) AS unique FROM owner; unique ------- 2
Para contar el número de combinaciones únicas de varias columnas, puedes envolver una consulta DISTINCT
como una subconsulta, y luego hacer una COUNT
en la subconsulta. La siguiente consulta devuelve el número de combinaciones únicas type
/open_to_public
.
SELECT COUNT(*) AS num_unique FROM (SELECT DISTINCT o.type, w.open_to_public FROM owner o JOIN waterfall w ON o.id = w.owner_id) my_subquery; num_unique ----------- 2
MySQL y PostgreSQL admiten el uso de la sintaxis COUNT(DISTINCT)
en varias columnas. Las dos consultas siguientes son equivalentes a la consulta anterior, sin necesidad de una subconsulta:
-- MySQL equivalent SELECT COUNT(DISTINCT o.type, w.open_to_public) AS num_unique FROM owner o JOIN waterfall w ON o.id = w.owner_id; -- PostgreSQL equivalent SELECT COUNT(DISTINCT (o.type, w.open_to_public)) AS num_unique FROM owner o JOIN waterfall w ON o.id = w.owner_id; num_unique ----------- 2
La cláusula FROM
La cláusula FROM
se utiliza para especificar la fuente de los datos que quieres recuperar. El caso más sencillo es nombrar una única tabla o vista en la cláusula FROM
de la consulta.
SELECT name FROM waterfall;
Puedes calificar una tabla o vista con un nombre de base de datos o de esquema utilizando la notación de punto. La siguiente consulta recupera datos específicamente de la tabla waterfall
dentro del esquema sqlbook
:
SELECT name FROM sqlbook.waterfall;
Desde varias tablas
En lugar de recuperar datos de una tabla, a menudo querrás reunir datos de varias tablas. La forma más habitual de hacerlo es utilizando una cláusula JOIN
dentro de la cláusula FROM
. La siguiente consulta recupera datos de las tablas waterfall
y tour
y muestra una única tabla de resultados.
SELECT * FROM waterfall w JOIN tour t ON w.id = t.stop; id name ... name stop ... ----- --------------- --------- ----- 1 Munising Falls M-28 1 1 Munising Falls Munising 1 2 Tannery Falls Munising 2 3 Alger Falls M-28 3 3 Alger Falls Munising 3 ...
Vamos a desglosar cada parte del bloque de código.
Alias de la tabla
waterfall w JOIN tour t
Las tablas waterfall
y tour
reciben los alias de tabla w
y t
, que son nombres temporales para las tablas dentro de la consulta. Los alias de tabla no son necesarios en una cláusula JOIN
, pero son muy útiles para acortar los nombres de las tablas a las que hay que hacer referencia dentro de las cláusulas ON
y SELECT
.
ÚNETE A ... EN ...
waterfall w JOIN tour t ON w.id = t.stop
Estas dos tablas se unen mediante la palabra clave JOIN
. Una cláusula JOIN
siempre va seguida de una cláusula ON
, que especifica cómo deben enlazarse las tablas. En este caso, la id
de la cascada de la tabla waterfall
debe coincidir con la stop
de la cascada de la tabla tour
.
Nota
Puede que veas las cláusulas FROM
, JOIN
, y ON
en líneas diferentes o con sangría. Esto no es necesario, pero resulta útil para facilitar la lectura, sobre todo cuando unes muchas tablas.
Tabla de resultados
Una consulta siempre da como resultado una única tabla. La tabla waterfall
tiene 12 columnas y la tabla tour
tiene 3 columnas. Tras unir estas tablas, la tabla de resultados tiene 15 columnas.
id name ... name stop ... ----- --------------- --------- ----- 1 Munising Falls M-28 1 1 Munising Falls Munising 1 2 Tannery Falls Munising 2 3 Alger Falls M-28 3 3 Alger Falls Munising 3 ...
Observarás que hay dos columnas llamadas name
en la tabla de resultados. La primera es de la tabla waterfall
, y lasegunda es de la tabla tour
. Para referirte a ellas en la cláusula SELECT
, tendrías que calificar los nombres de las columnas.
SELECT w.name, t.name FROM waterfall w JOIN tour t ON w.id = t.stop; name name --------------- --------- Munising Falls M-28 Munising Falls Munising Tannery Falls Munising ...
Para diferenciar las dos columnas, también querrás poner un alias a los nombres de las columnas.
SELECT w.name AS waterfall_name, t.name AS tour_name FROM waterfall w JOIN tour t ON w.id = t.stop; waterfall_name tour_name --------------- ---------- Munising Falls M-28 Munising Falls Munising Tannery Falls Munising Alger Falls M-28 Alger Falls Munising ...
variaciones de JOIN
En el ejemplo anterior, si una cascada no aparece en ningún recorrido, no aparecería en la tabla de resultados. Si quisieras ver todas las cascadas en los resultados, tendrías que utilizar otro tipo de unión.
Hay varios tipos de unión utilizados en SQL, que se tratan con más detalle en "Unir tablas", en el Capítulo 9.
Desde Subconsultas
Una subconsulta es una consulta anidada dentro de otra consulta. Las subconsultas dentro de la cláusula FROM
deben ser sentencias SELECT
independientes, lo que significa que no hacen referencia alguna a la consulta externa y pueden ejecutarse por sí solas.
Nota
Una subconsulta dentro de la cláusula FROM
también se conoce como tabla derivada, porque la subconsulta acaba actuando esencialmente como una tabla mientras dura la consulta.
La siguiente consulta enumera todas las cascadas de titularidad pública, con la parte de la subconsulta en negrita.
SELECT w.name AS waterfall_name, o.name AS owner_name FROM (SELECT * FROM owner WHERE type = 'public') o JOIN waterfall w ON o.id = w.owner_id; waterfall_name owner_name --------------- --------------- Little Miners Pictured Rocks Miners Falls Pictured Rocks Munising Falls Pictured Rocks Wagner Falls MI DNR
Es importante comprender el orden en que se ejecuta la consulta.
Paso 1: Ejecuta la subconsulta
Primero se ejecuta el contenido de la subconsulta. Puedes ver que el resultado es una tabla sólo de propietarios públicos:
SELECT * FROM owner WHERE type = 'public'; id name phone type ----- --------------- ------------- ------- 1 Pictured Rocks 906.387.2607 public 4 MI DNR 906.228.6561 public
Volviendo a la consulta original, verás que la subconsulta va seguida inmediatamente de la letra o
. Éste es el nombre temporal, o alias, que estamos asignando a los resultados de la subconsulta.
Nota
Los alias son necesarios para las subconsultas dentro de la cláusula FROM
en MySQL, PostgreSQL y SQL Server, pero no en Oracle y SQLite.
Paso 2: Ejecuta la consulta completa
A continuación, puedes pensar que la letra o
ocupa el lugar de la subconsulta. La consulta se ejecuta ahora como de costumbre.
SELECT w.name AS waterfall_name, o.name AS owner_name FROM o JOIN waterfall w ON o.id = w.owner_id; waterfall_name owner_name --------------- --------------- Little Miners Pictured Rocks Miners Falls Pictured Rocks Munising Falls Pictured Rocks Wagner Falls MI DNR
¿Por qué utilizar una subconsulta en la cláusula FROM?
La principal ventaja de utilizar subconsultas es que puedes convertir un problema grande en otros más pequeños. Aquí tienes dos ejemplos:
- Ejemplo 1: Múltiples pasos para llegar a los resultados
-
Supongamos que quieres hallar el número medio de paradas de un recorrido. En primer lugar, tendrías que hallar el número de paradas de cada recorrido y, a continuación, calcular la media de los resultados.
La siguiente consulta encuentra el número de paradas de cada recorrido:
SELECT name, MAX(stop) as num_stops FROM tour GROUP BY name; name num_stops --------- ---------- M-28 11 Munising 6 US-2 14
Entonces podrías convertir la consulta en una subconsulta y escribir otra consulta a su alrededor para encontrar la media:
SELECT AVG(num_stops) FROM (SELECT name, MAX(stop) as num_stops FROM tour GROUP BY name) tour_stops; AVG(num_stops) ----------------- 10.3333333333333
- Ejemplo 2: La tabla de la cláusula FROM es demasiado grande
-
El objetivo original era hacer una lista de todas las cascadas de titularidad pública. En realidad, esto puede hacerse sin una subconsulta y, en su lugar, con
JOIN
:SELECT w.name AS waterfall_name, o.name AS owner_name FROM owner o JOIN waterfall w ON o.id = w.owner_id WHERE o.type = 'public'; waterfall_name owner_name --------------- --------------- Little Miners Pictured Rocks Miners Falls Pictured Rocks Munising Falls Pictured Rocks Wagner Falls MI DNR
Supongamos que la consulta tarda mucho tiempo en ejecutarse. Esto puede ocurrir cuando unes tablas enormes (piensa en decenas de millones de filas). Hay varias formas de reescribir la consulta para acelerarla, y una de ellas es utilizar una subconsulta.
Como sólo nos interesan los propietarios públicos, podemos escribir primero una subconsulta que filtre todos los propietarios privados. La tabla
owner
, más pequeña, se uniría entonces a la tablawaterfall
, lo que llevaría menos tiempo y produciría los mismos resultados.SELECT w.name AS waterfall_name, o.name AS owner_name FROM (SELECT * FROM owner WHERE type = 'public') o JOIN waterfall w ON o.id = w.owner_id; waterfall_name owner_name --------------- --------------- Little Miners Pictured Rocks Miners Falls Pictured Rocks Munising Falls Pictured Rocks Wagner Falls MI DNR
Estos son sólo dos de los muchos ejemplos de cómo se pueden utilizar las subconsultas para dividir una consulta mayor en pasos más pequeños.
La cláusula WHERE
La cláusula WHERE
se utiliza para restringir los resultados de la consulta a sólo las filas de interés, o dicho de forma sencilla, es el lugar donde filtrar los datos. Rara vez querrás mostrar todas las filas de una tabla, sino las que coincidan con criterios específicos.
Consejo
Cuando explores una tabla con millones de filas, nunca querrás hacer un SELECT * FROM my_table;
porque tardará un tiempo innecesariamente largo en ejecutarse.
En su lugar, es una buena idea filtrar los datos. Dos formas habituales de hacerlo son
- Filtra por una columna dentro de la cláusula
WHERE
-
Mejor aún, filtra por una columna que ya esté indexada para que la recuperación sea aún más rápida.
SELECT * FROM my_table WHERE year_id = 2021;
- Muestra las primeras filas de datos con la cláusula
LIMIT
cláusula -
(o
WHERE ROWNUM <= 10
en Oracle oSELECT TOP 10 *
en SQL Server)SELECT * FROM my_table LIMIT 10;
La siguiente consulta busca todas las cascadas que no contengan Cataratas en el nombre. Encontrarás más información sobre la palabra clave LIKE
en el capítulo 7.
SELECT id, name FROM waterfall WHERE name NOT LIKE '%Falls%'; id name ----- ---------------- 7 Little Miners 14 Rapid River Fls
La sección en negrita suele denominarse declaración condicional o predicado. El predicado realiza una comparación lógica para cada fila de datos que da como resultado TRUE
/FALSE
/UNKNOWN
.
La tabla waterfall
tiene 16 filas. Para cada fila, comprueba siel nombre dela cascada contiene o no Cataratas. Si no contiene Cataratas, entonces el predicado name NOT LIKE '%Falls%'
es TRUE
, y la fila se devuelve en los resultados, como ocurrió con las dosfilas anteriores.
Predicados múltiples
También es posible combinar varios predicados con operadores como AND
o OR
. El siguiente ejemplo muestra cascadas sin Cataratas en su nombre y que tampoco tienen propietario:
SELECT id, name FROM waterfall WHERE name NOT LIKE '%Falls%' AND owner_id IS NULL; id name ----- ---------------- 14 Rapid River Fls
Encontrarás más detalles sobre los operadores en Operadores, en el capítulo 7.
Filtrar en subconsultas
Una subconsulta es una consulta anidada dentro de otra consulta, y la cláusula WHERE
es un lugar habitual para encontrar una. El siguiente ejemplo recupera las cascadas de acceso público situadas en el condado de Alger:
SELECT w.name FROM waterfall w WHERE w.open_to_public = 'y' AND w.county_id IN ( SELECT c.id FROM county c WHERE c.name = 'Alger'); name --------------- Munising Falls Tannery Falls Alger Falls ...
Nota
A diferencia de las subconsultas dentro de la cláusula SELECT
o la cláusula FROM
, las subconsultas en la cláusula WHERE
no requieren un alias. De hecho, obtendrás un error si incluyes un alias.
¿Por qué utilizar una subconsulta en la cláusula WHERE?
El objetivo original era recuperar las cascadas de acceso público situadas en el condado de Alger. Si tuvieras que escribir esta consulta desde cero, probablemente empezarías con lo siguiente:
SELECT w.name FROM waterfall w WHERE w.open_to_public = 'y';
Llegados a este punto, ya tienes todas las cascadas que son de acceso público. El toque final es encontrar las que están específicamente en el condado de Alger. Sabes que la tabla waterfall
no tiene una columna con el nombre del condado, pero la tabla county
sí.
Tienes dos opciones para obtener el nombre del condado en los resultados. Puedes (1) escribir una subconsulta dentro de la cláusula WHERE
que extraiga específicamente la información del condado de Alger o (2) unir las tablas waterfall
y county
:
-- Subquery in WHERE clause SELECT w.name FROM waterfall w WHERE w.open_to_public = 'y' AND w.county_id IN ( SELECT c.id FROM county c WHERE c.name = 'Alger');
o:
-- JOIN clause SELECT w.name FROM waterfall w INNER JOIN county c ON w.county_id = c.id WHERE w.open_to_public = 'y' AND c.name = 'Alger'; name --------------- Munising Falls Tannery Falls Alger Falls ...
Las dos consultas producen los mismos resultados. La ventaja del primer enfoque es que las subconsultas suelen ser más fáciles de entender que las uniones. La ventaja del segundo enfoque es que las uniones suelen ejecutarse más rápido que las subconsultas.
Otras formas de filtrar datos
La cláusula WHERE
no es el único lugar dentro de una sentencia SELECT
para filtrar filas de datos.
-
FROM
cláusula Al unir tablas, la cláusulaON
especifica cómo deben enlazarse. Aquí es donde puedes incluir condiciones para restringir las filas de datos devueltas por la consulta. Para más detalles, consulta Unir tablas en el Capítulo 9. -
HAVING
cláusula: Si hay agregaciones dentro de la sentenciaSELECT
, la cláusulaHAVING
es donde se especifica cómo deben filtrarse las agregaciones. Consulta "La cláusula HAVING" para más detalles. -
LIMIT
cláusula LIMIT: Para mostrar un número concreto de filas, puedes utilizar la cláusula LIMIT. En Oracle, esto se hace conWHERE ROWNUM
y en SQL Server, conSELECT TOP
. Para más detalles, consulta "La cláusula LIMIT" en este capítulo.
La cláusula GROUP BY
El propósito de la cláusula GROUP BY
es reunir las filas en grupos y resumir las filas dentro de los grupos de alguna manera, devolviendo finalmente sólo una fila por grupo. A veces se denomina a esto "trocear" las filas en grupos y "enrollar" las filas de cada grupo.
La siguiente consulta cuenta el número de cascadas a lo largo de cada uno de los recorridos:
SELECT t.name AS tour_name, COUNT(*) AS num_waterfalls FROM waterfall w INNER JOIN tour t ON w.id = t.stop GROUP BY t.name; tour_name num_waterfalls ---------- --------------- M-28 6 Munising 6 US-2 4
Hay dos partes en las que centrarse aquí:
-
La recopilación de filas, que se especifica en la cláusula
GROUP BY
-
La integración de filas dentro de grupos, que se especifica en la cláusula
SELECT
Paso 1: Recogida de filas
En la cláusula GROUP BY
:
GROUP BY t.name
decimos que nos gustaría que mirara todas las filas de datos y agrupara las cascadas de la excursión M-28, todas las cascadas de la excursión Munising, etc. Entre bastidores, los datos se agrupan así:
tour_name waterfall_name ---------- ---------------- M-28 Munising Falls M-28 Alger Falls M-28 Scott Falls M-28 Canyon Falls M-28 Agate Falls M-28 Bond Falls Munising Munising Falls Munising Tannery Falls Munising Alger Falls Munising Wagner Falls Munising Horseshoe Falls Munising Miners Falls US-2 Bond Falls US-2 Fumee Falls US-2 Kakabika Falls US-2 Rapid River Fls
Paso 2: El resumen de filas
En la cláusula SELECT
,
SELECT t.name AS tour_name, COUNT(*) AS num_waterfalls
decimos que para cada grupo, o cada recorrido, queremos contar el número de filas de datos del grupo. Como cada fila representa una cascada, el resultado sería el número total de cascadas a lo largo de cada recorrido.
La función COUNT()
se conoce más formalmente como función agregada, o función que resume muchas filas de datos en un único valor. Puedes encontrar más funciones agregadas en "Funciones agregadas", en el Capítulo 7.
Advertencia
En este ejemplo, COUNT(*)
devuelve el número de cascadas de cada recorrido. Sin embargo, esto sólo se debe a que cada fila de datos de las tablas waterfall
y tour
representa una única cascada.
Si una única cascada apareciera en varias filas, COUNT(*)
daría como resultado un valor mayor del esperado. En este caso, podrías utilizar COUNT(DISTINCT waterfall_name)
en su lugar para encontrar las cascadas únicas. Puedes encontrar más detalles en COUNT and DISTINCT
.
La clave es que es importante volver a comprobar manualmente los resultados de la función de agregado para asegurarte de que resume los datos de la forma que pretendías.
Ahora que se han creado los grupos con la cláusula GROUP BY
, la función de agregado se aplicará una vez a cada grupo:
tour_name COUNT(*) ---------- --------- M-28 6 M-28 M-28 M-28 M-28 M-28 Munising 6 Munising Munising Munising Munising Munising US-2 4 US-2 US-2 US-2
Las columnas a las que no se ha aplicado una función de agregado, que en este caso es la columna tour_name
, se contraen ahora en un solo valor:
tour_name COUNT(*) ---------- --------- M-28 6 Munising 6 US-2 4
Nota
Este colapso de muchas filas detalladas en una fila agregada significa que al utilizar una cláusula GROUP BY
, la cláusula SELECT
sólo debe contener:
-
Todas las columnas de la cláusula
GROUP BY
:t.name
-
Agregaciones:
COUNT(*)
SELECT t.name AS tour_name, COUNT(*) AS num_waterfalls ... GROUP BY t.name;
No hacerlo podría dar lugar a un mensaje de error o devolver valores inexactos.
Para situaciones de agrupación más complejas, como ROLLUP
, CUBE
y GROUPING SETS
, ve a "Agrupar y resumir" en el capítulo 8.
La cláusula HAVING
La cláusula HAVING
impone restricciones a las filas devueltas por una consulta GROUP BY
. En otras palabras, te permite filtrar los resultados después de aplicar GROUP BY
.
Nota
Una cláusula HAVING
siempre sigue inmediatamente a una cláusula GROUP BY
. Sin una cláusula GROUP BY
, no puede haber cláusula HAVING
.
Se trata de una consulta que enumera el número de cascadas de cada recorrido utilizando una cláusula GROUP BY
:
SELECT t.name AS tour_name, COUNT(*) AS num_waterfalls FROM waterfall w INNER JOIN tour t ON w.id = t.stop GROUP BY t.name;
tour_name num_waterfalls ---------- --------------- M-28 6 Munising 6 US-2 4
Supongamos que sólo queremos listar los recorridos que tienen exactamente seis paradas. Para ello, añadirías una cláusula HAVING
después de la cláusula GROUP BY
:
SELECT t.name AS tour_name, COUNT(*) AS num_waterfalls FROM waterfall w INNER JOIN tour t ON w.id = t.stop GROUP BY t.name HAVING COUNT(*) = 6; tour_name num_waterfalls ---------- --------------- M-28 6 Munising 6
Verás que la cláusula HAVING
remite a la agregación COUNT(*)
,
SELECT COUNT(*) AS num_waterfalls ... HAVING COUNT(*) = 6;
y no el alias,
# code will not run SELECT COUNT(*) AS num_waterfalls ... HAVING num_waterfalls = 6;
El motivo es el orden de ejecución de las cláusulas. La cláusula SELECT
se escribe antes que la cláusula HAVING
. Sin embargo, la cláusula SELECT
se ejecuta en realidad después de la cláusula HAVING
.
Eso significa que el alias num_waterfalls
de la cláusula SELECT
no existe en el momento en que se ejecuta la cláusula HAVING
. En su lugar, la cláusula HAVING
debe hacer referencia a la agregación bruta COUNT(*)
.
La cláusula ORDER BY
La cláusula ORDER BY
se utiliza para especificar cómo quieres que se ordenen los resultados de una consulta.
La siguiente consulta devuelve una lista de propietarios y cascadas, sin ordenar:
SELECT COALESCE(o.name, 'Unknown') AS owner, w.name AS waterfall_name FROM waterfall w LEFT JOIN owner o ON w.owner_id = o.id; owner waterfall_name ---------------- --------------- Pictured Rocks Munising Falls Michigan Nature Tannery Falls AF LLC Alger Falls MI DNR Wagner Falls Unknown Horseshoe Falls ...
La siguiente consulta devuelve a la misma lista, pero primero ordenada alfabéticamente por propietario y luego por cascada:
SELECT COALESCE(o.name, 'Unknown') AS owner, w.name AS waterfall_name FROM waterfall w LEFT JOIN owner o ON w.owner_id = o.id ORDER BY owner, waterfall_name; owner waterfall_name ---------------- --------------- AF LLC Alger Falls MI DNR Wagner Falls Michigan Nature Tannery Falls Michigan Nature Twin Falls #1 Michigan Nature Twin Falls #2 ...
La ordenación por defecto es ascendente, lo que significa que el texto irá de la A a la Z y los números de menor a mayor. Puedes utilizar las palabras clave ASCENDING
y DESCENDING
(que pueden abreviarse como ASC
y DESC
) para controlar la ordenación de cadacolumna.
Lo siguiente es una modificación de la ordenación anterior, pero esta vez ordena los nombres de los propietarios en orden inverso:
SELECT COALESCE(o.name, 'Unknown') AS owner, w.name AS waterfall_name ... ORDER BY owner DESC, waterfall_name ASC; owner waterfall_name ---------------- --------------- Unknown Agate Falls Unknown Bond Falls Unknown Canyon Falls ...
Puedes ordenar por columnas y expresiones que no estén en tu lista SELECT
:
SELECT COALESCE(o.name, 'Unknown') AS owner, w.name AS waterfall_name FROM waterfall w LEFT JOIN owner o ON w.owner_id = o.id ORDER BY o.id DESC, w.id; owner waterfall_name ---------------- --------------- MI DNR Wagner Falls AF LLC Alger Falls Michigan Nature Tannery Falls ...
También puedes ordenar por posición numérica de columna:
SELECT COALESCE(o.name, 'Unknown') AS owner, w.name AS waterfall_name ... ORDER BY 1 DESC, 2 ASC; owner waterfall_name ---------------- --------------- Unknown Agate Falls Unknown Bond Falls Unknown Canyon Falls ...
Como las filas de una tabla SQL no están ordenadas, si no incluyes una cláusula ORDER BY
en una consulta, cada vez que la ejecutes, los resultados podrían mostrarse en un orden distinto.
La cláusula LÍMITE
Al visualizar rápidamente una tabla, es una buena práctica devolver un número limitado de filas en lugar de toda la tabla.
MySQL, PostgreSQL y SQLite admiten la cláusula LIMIT
. Oracle y SQL Server utilizan una sintaxis diferente con la mismafuncionalidad:
-- MySQL, PostgreSQL, and SQLite SELECT * FROM owner LIMIT 3; -- Oracle SELECT * FROM owner WHERE ROWNUM <= 3; -- SQL Server SELECT TOP 3 * FROM owner; id name phone type --- ---------------- ------------- -------- 1 Pictured Rocks 906.387.2607 public 2 Michigan Nature 517.655.5655 private 3 AF LLC private
Otra forma de limitar el número de filas devueltas es filtrar por una columna dentro de la cláusula WHERE
cláusula. El filtrado se ejecutará aún más rápido si la columna está indexada.
Get Guía SQL de Bolsillo, 4ª Edición now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.