Buenas prácticas en SQL
Escribir SQL no es solo lograr que la consulta devuelva el resultado esperado, sino escribirla de forma que cualquier otra persona (o tú mismo en seis meses) pueda leerla y entenderla rápidamente. En este post vamos a repasar recomendaciones prácticas sobre:
- Código limpio y tabulado
- Uso correcto de alias
- Funciones de ventana (window functions)
- Tipos de
JOINy cuándo usar cada uno
1. Código limpio y tabulado
Una consulta SQL mal formateada es difícil de leer, aunque sea correcta. Algunas reglas simples ayudan mucho:
- Una cláusula por línea (
SELECT,FROM,WHERE,GROUP BY,ORDER BY, etc.) - Los campos del
SELECT, uno por línea y alineados con tabulación - Palabras clave en mayúsculas para diferenciarlas de nombres de columnas/tablas
- Indentar las condiciones que dependen de otra cláusula
Mal formateado:
| |
Bien formateado:
| |
Con consultas cortas la diferencia no se nota tanto, pero en consultas de 100+ líneas con varios
JOINy subconsultas, un buen formato es la diferencia entre depurar en minutos o en horas.
Recomendaciones generales
- Usa un largo de línea razonable, evita líneas de 200 caracteres.
- Agrupa condiciones relacionadas con paréntesis y una condición por línea cuando el
WHEREcrece. - Usa CTEs (
WITH) en lugar de subconsultas anidadas cuando la lógica se vuelve compleja, son mucho más legibles.
| |
2. Uso correcto de alias
Los alias (AS) sirven para acortar nombres de tablas y para nombrar columnas calculadas. Bien usados, hacen la consulta mucho más legible; mal usados, la vuelven confusa.
Recomendaciones
- Usa siempre
ASpara declarar el alias, aunque sea opcional en muchos motores. Deja explícita la intención. - Alias cortos pero descriptivos para tablas: prefiere iniciales con sentido (
cparaclientes,oparaordenes) en vez de letras aleatorias (a,b,x). - No abuses de alias de una sola letra en consultas con muchas tablas, ahí es mejor usar abreviaturas de 2-3 letras (
cli,ord,prod). - Alias en columnas calculadas siempre, para que el resultado tenga un nombre claro.
| |
Sin alias en las columnas calculadas, el resultado se vería con nombres como COUNT(o.id) o SUM(o.total), poco amigables para quien consuma el reporte.
Evita reutilizar el mismo alias para cosas distintas dentro de la misma consulta (por ejemplo usar
tparatotalen unSELECTy paratablaen otroFROM). Es una fuente común de confusión al leer consultas largas.
3. Funciones de ventana (Window Functions)
Las funciones de ventana permiten hacer cálculos sobre un conjunto de filas relacionadas con la fila actual, sin colapsar el resultado como lo hace GROUP BY. Se definen con OVER().
Sintaxis general
| |
PARTITION BY: agrupa las filas en “particiones” (similar aGROUP BY, pero sin colapsar filas).ORDER BY: define el orden dentro de cada partición, necesario para funciones comoROW_NUMBERo los acumulados.
Casos de uso comunes
Ranking de ventas por cliente
| |
ROW_NUMBER(): numera filas de forma única, útil para obtener el “top N por grupo” o eliminar duplicados.RANK()/DENSE_RANK(): similares aROW_NUMBER, pero permiten empates.RANKdeja huecos en la numeración tras un empate,DENSE_RANKno.
Total acumulado (running total)
| |
Útil para reportes financieros, saldos acumulados o métricas de crecimiento día a día.
Comparar con la fila anterior/siguiente
| |
LAG(): trae el valor de la fila anterior dentro de la partición.LEAD(): trae el valor de la fila siguiente.
Ideal para calcular variaciones entre periodos (por ejemplo, cuánto aumentó o disminuyó una compra respecto a la anterior).
Regla práctica: si necesitas un cálculo agregado (suma, conteo, ranking, promedio) pero sin perder el detalle de cada fila, piensa en una función de ventana antes que en un
GROUP BYcon subconsultas.
4. Tipos de JOIN y cuándo usar cada uno
Elegir el JOIN correcto es una de las decisiones que más impacta tanto el resultado como el rendimiento de una consulta.
INNER JOIN
Devuelve solo las filas que tienen coincidencia en ambas tablas.
| |
Cuándo usarlo: cuando solo te interesan los registros que existen en ambas tablas. Por ejemplo, clientes que sí tienen al menos una orden.
LEFT JOIN (o LEFT OUTER JOIN)
Devuelve todas las filas de la tabla izquierda, y las coincidencias de la derecha si existen (si no, rellena con NULL).
| |
Cuándo usarlo: cuando necesitas conservar todos los registros de la tabla principal, tengan o no relación. Por ejemplo, listar todos los clientes, incluso los que nunca compraron (para detectar clientes inactivos, o.total vendría NULL).
| |
RIGHT JOIN (o RIGHT OUTER JOIN)
Es el espejo del LEFT JOIN: conserva todas las filas de la tabla derecha.
| |
Cuándo usarlo: en la práctica es poco común, porque cualquier RIGHT JOIN se puede reescribir como un LEFT JOIN invirtiendo el orden de las tablas, que suele ser más legible. Aun así, es útil conocerlo para leer consultas de terceros.
FULL JOIN (o FULL OUTER JOIN)
Devuelve todas las filas de ambas tablas, con NULL donde no hay coincidencia.
| |
Cuándo usarlo: cuando necesitas ver el panorama completo de dos tablas, incluyendo lo que no coincide en ninguna de las dos direcciones. Por ejemplo, auditar diferencias entre dos sistemas (clientes que están en un sistema pero no en otro y viceversa).
CROSS JOIN
Genera el producto cartesiano: cada fila de una tabla combinada con cada fila de la otra.
| |
Cuándo usarlo: para generar combinaciones, por ejemplo todas las combinaciones posibles de talla y color de un producto antes de crear el inventario. Se debe usar con cuidado, ya que el número de filas resultante es filas_tabla1 x filas_tabla2 y puede crecer muy rápido.
SELF JOIN
No es un tipo de JOIN distinto, sino una tabla unida consigo misma, usando alias para diferenciarla.
| |
Cuándo usarlo: cuando una tabla tiene una relación jerárquica o de referencia hacia sí misma, como empleados y sus jefes, o categorías con subcategorías.
Resumen de recomendaciones
| Práctica | Recomendación |
|---|---|
| Formato | Una cláusula y un campo por línea, palabras clave en mayúsculas |
| Alias | Usar siempre AS, alias cortos pero descriptivos, sin ambigüedad |
| Window Functions | Úsalas cuando necesites cálculos agregados sin perder el detalle por fila |
| INNER JOIN | Solo coincidencias en ambas tablas |
| LEFT / RIGHT JOIN | Conservar todos los registros de una tabla, coincidan o no |
| FULL JOIN | Ver todo de ambas tablas, incluyendo lo que no coincide |
| CROSS JOIN | Generar combinaciones, usar con cuidado por el volumen de filas |
| SELF JOIN | Relaciones jerárquicas dentro de la misma tabla |
Aplicar estas prácticas de forma consistente hace que tus consultas sean más fáciles de mantener, de depurar y de compartir con el resto del equipo.