
SQL: Fundamentos de SELECT, FROM y WHERE
- Dacadev
- Programación
- 5 de junio de 2026
Tabla de Contenido
Cuando trabajas con una base de datos relacional, la calidad del sistema depende de consultas legibles y precisas. Las sentencias básicas de SQL como SELECT, FROM y WHERE definen qué datos recuperas, desde dónde los tomas y bajo qué condiciones entran al resultado final. Este es el primer artículo de la serie de SQL.
Note
En este artículo aprenderás cómo se organiza una consulta SQL, qué rol cumplen SELECT, FROM, WHERE, GROUP BY, HAVING y ORDER BY, y cómo usar alias, tablas derivadas, tablas temporales y vistas para construir consultas más claras.
Qué es una base de datos y cómo se estructura una consulta SQL
Info
Una base de datos no es más que un conjunto de información relacionada. En SQL trabajamos sobre esa información mediante sentencias que describen qué datos queremos leer, filtrar, agrupar u ordenar.
SQL permite expresar consultas declarativas: describes el resultado esperado y el motor decide el plan de ejecución, aplica optimizaciones y devuelve un result set.
Las cláusulas principales de una consulta suelen aparecer en este orden lógico:
| Cláusula | Propósito |
|---|---|
select | Determina qué columnas incluir en el result set de la consulta |
from | Identifica las tablas de las que se extraen los datos y cómo se unen |
where | Filtra los registros no deseados |
group by | Agrupa filas por valores de columna comunes |
having | Filtra los grupos no deseados |
order by | Ordena las filas del resultado final por una o más columnas |
SELECT: definir las columnas del resultado
Tip
La cláusula SELECT determina cuáles columnas, expresiones o valores calculados se incluyen en el resultado de la consulta.
SELECT es la parte visible de la consulta. Ahí defines columnas, valores constantes, expresiones calculadas o resultados procesados por funciones integradas.
Consideremos este ejemplo usando language:
mysql> SELECT language_id,
-> 'COMMON' language_usage,
-> language_id * 3.1415927 lang_pi_value,
-> upper(name) language_name
-> FROM language;
+-------------+----------------+---------------+---------------+
| language_id | language_usage | lang_pi_value | language_name |
+-------------+----------------+---------------+---------------+
| 1 | COMMON | 3.1415927 | ENGLISH |
| 2 | COMMON | 6.2831854 | ITALIAN |
| 3 | COMMON | 9.4247781 | JAPANESE |
| 4 | COMMON | 12.5663708 | MANDARIN |
| ... | ... | ... | ... |
+-------------+----------------+---------------+---------------+
6 rows in set (0.04 sec)
Este SELECT combina una columna real, un literal, una expresión aritmética y una función. Cada expresión forma una columna del resultado.
Reglas prácticas:
- Usa
*solo cuando realmente necesitas todas las columnas. - Selecciona columnas específicas para reducir ruido y transferencia de datos.
- Usa
ASpara alias explícitos en columnas calculadas o renombradas. - Aplica operaciones, funciones integradas o expresiones cuando aporte claridad.
- Usa
DISTINCTpara eliminar duplicados según las columnas seleccionadas.
Warning
Evita usar SELECT * por defecto en consultas que respaldan APIs, reportes o procesos críticos. Cuando el esquema cambia, el resultado también cambia, y eso puede romper consumidores que esperan columnas específicas.
FROM: declarar el origen de los datos
Tip
La cláusula FROM define las tablas usadas por la consulta y también la forma en que esas tablas se relacionan entre sí.
FROM indica de dónde salen las filas. Puede apuntar a tablas permanentes, derivadas, temporales o vistas.
Tablas permanentes
Las tablas permanentes son creadas con CREATE TABLE: datos persistentes, definidos en el esquema y disponibles entre sesiones.
Ejemplo mínimo:
SELECT language_id, name
FROM language;
Tablas derivadas
Una tabla derivada es una subconsulta usada dentro de FROM. Vive solo durante la ejecución y permite aislar una etapa intermedia.
mysql> SELECT concat(cust.last_name, ', ', cust.first_name) full_name
-> FROM
-> (SELECT first_name, last_name, email
-> FROM customer
-> WHERE first_name = 'JESSIE'
-> ) cust;
+---------------+
| full_name |
+---------------+
| BANKS, JESSIE |
| MILAM, JESSIE |
+---------------+
2 rows in set (0.00 sec)
La subconsulta filtra clientes llamados JESSIE. La consulta externa usa ese conjunto como cust y construye full_name.
Tablas temporales
Las tablas temporales materializan datos intermedios durante una sesión, transacción o proceso puntual.
Info
Las tablas temporales se comportan como tablas normales, pero los datos insertados desaparecen en algún momento, usualmente al cerrar la sesión de base de datos o finalizar la transacción, según el motor utilizado.
mysql> CREATE TEMPORARY TABLE actors_j
-> (actor_id smallint(5),
-> first_name varchar(45),
-> last_name varchar(45)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO actors_j
-> SELECT actor_id, first_name, last_name
-> FROM actor
-> WHERE last_name LIKE 'J%';
Query OK, 7 rows affected (0.03 sec)
Records: 7 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM actors_j;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 119 | WARREN | JACKMAN |
| 131 | JANE | JACKMAN |
| 8 | MATTHEW | JOHANSSON |
| 64 | RAY | JOHANSSON |
| ... | ... | ... |
+----------+------------+-----------+
7 rows in set (0.00 sec)
Este patrón es práctico cuando un proceso reutiliza un subconjunto de datos varias veces. Conviene medir su impacto porque materializar datos tiene costo.
Vistas
Una vista es una tabla virtual creada con CREATE VIEW. Normalmente encapsula una consulta y la expone como fuente reutilizable.
mysql> CREATE VIEW cust_vw AS
-> SELECT customer_id, first_name, last_name, active
-> FROM customer;
Query OK, 0 rows affected (0.12 sec)
mysql> SELECT first_name, last_name
-> FROM cust_vw
-> WHERE active = 0;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| SANDRA | MARTIN |
| JUDITH | COX |
| SHEILA | WELLS |
| ERICA | MATTHEWS |
| HEIDI | LARSON |
| ... | ... |
| TERRANCE | ROUSH |
+------------+-----------+
15 rows in set (0.00 sec)
Las vistas encapsulan lógica compartida y pueden exponer solo ciertas columnas a consumidores internos.
Alias: mejorar legibilidad sin cambiar el modelo
Los alias permiten referenciar tablas y columnas con nombres más cortos. Esto evita redundancia y mejora la lectura, especialmente cuando hay joins o nombres de tabla largos.
Observemos este ejemplo:
SELECT c.first_name, c.last_name,
time(r.rental_date) rental_time
FROM customer c
INNER JOIN rental r
ON c.customer_id = r.customer_id
WHERE date(r.rental_date) = '2005-06-14';
En este caso, customer se referencia como c y rental como r. La consulta queda compacta y cada columna mantiene un origen explícito.
WHERE: filtrar filas antes del resultado final
Tip
La cláusula WHERE es el mecanismo para excluir filas no deseadas del result set.
WHERE concentra buena parte de la lógica de una consulta. Ahí combinas operadores, comparaciones, funciones y paréntesis para expresar condiciones precisas.
mysql> SELECT title, rating, rental_duration
-> FROM film
-> WHERE (rating = 'G' AND rental_duration >= 7)
-> OR (rating = 'PG-13' AND rental_duration < 4);
+-------------------------+--------+-----------------+
| title | rating | rental_duration |
+-------------------------+--------+-----------------+
| ALABAMA DEVIL | PG-13 | 3 |
| BACKLASH UNDEFEATED | PG-13 | 3 |
| BILKO ANONYMOUS | PG-13 | 3 |
| BLANKET BEVERLY | G | 7 |
| BORROWERS BEDAZZLED | G | 7 |
| BRIDE INTRIGUE | G | 7 |
| CASPER DRAGONFLY | PG-13 | 3 |
| ... | ... | ... |
| WAR NOTTING | G | 7 |
| WORLD LEATHERNECKS | PG-13 | 3 |
+-------------------------+--------+-----------------+
68 rows in set (0.00 sec)
La condición usa dos grupos lógicos. Los paréntesis hacen explícita la intención y reducen ambigüedad cuando se combinan AND y OR.
Warning
Cuando mezclas AND y OR, usa paréntesis aunque el motor tenga reglas de precedencia. La consulta queda más legible y disminuye el riesgo de devolver más filas de las esperadas.
GROUP BY y HAVING: agrupar datos y filtrar agregados
GROUP BY agrupa filas por valores comunes de una o más columnas y permite aplicar agregados como count, sum, avg, min o max. HAVING opera después de la agrupación: filtra grupos, no filas individuales.
mysql> SELECT c.first_name, c.last_name, count(*)
-> FROM customer c
-> INNER JOIN rental r
-> ON c.customer_id = r.customer_id
-> GROUP BY c.first_name, c.last_name
-> HAVING count(*) >= 40;
+------------+-----------+----------+
| first_name | last_name | count(*) |
+------------+-----------+----------+
| TAMMY | SANDERS | 41 |
| CLARA | SHAW | 42 |
| ELEANOR | HUNT | 46 |
| SUE | PETERS | 40 |
| ... | ... | ... |
+------------+-----------+----------+
7 rows in set (0.03 sec)
Aquí agrupamos rentas por cliente y dejamos solo clientes con 40 o más rentas. WHERE count(*) >= 40 no aplica porque WHERE se evalúa antes de calcular agregados.
ORDER BY: ordenar el resultado final
ORDER BY define el orden de las filas devueltas. Sin esta cláusula, no debes asumir un orden estable.
mysql> SELECT c.first_name, c.last_name,
-> time(r.rental_date) rental_time
-> FROM customer c
-> INNER JOIN rental r
-> ON c.customer_id = r.customer_id
-> WHERE date(r.rental_date) = '2005-06-14'
-> ORDER BY c.last_name;
+------------+-----------+-------------+
| first_name | last_name | rental_time |
+------------+-----------+-------------+
| DANIEL | CABRAL | 23:09:38 |
| CATHERINE | CAMPBELL | 23:17:03 |
| HERMAN | DEVORE | 23:35:09 |
| AMBER | DIXON | 23:42:56 |
| JOYCE | EDWARDS | 23:16:26 |
| ... | ... | ... |
+------------+-----------+-------------+
16 rows in set (0.01 sec)
En este caso, el resultado queda ordenado por last_name. También puedes ordenar por múltiples columnas y controlar la dirección con ASC o DESC.
Cierre
Las cláusulas básicas de SQL forman una cadena clara: SELECT define qué mostrar, FROM de dónde leer, WHERE filtra filas, GROUP BY agrupa, HAVING filtra grupos y ORDER BY estabiliza el orden final.
En el siguiente artículo de la serie profundizaremos en Filtrado de datos con la cláusula WHERE, donde analizaremos operadores, rangos, patrones, valores nulos y composición de condiciones con más detalle.
