DQL

Consultas con campos calculados – Funciones SQL

Para ejemplificar el uso de funciones del sistema de gestión de bases de datos se considera el siguiente modelo relacional:

Aunque cada sistema de gestión de bases de datos tiene funciones propias, respecto a funciones escalares (que trabajan sobre valores individuales y devuelven un valor por cada fila), todas ellas pueden clasificarse en funciones numéricas, de texto, fecha y hora, lógicas y de conversión. Además, todos ellos cuentan también con funciones básicas de agregado (que funcionan sobre un conjunto de filas y devuelven un único valor resumido).

Funciones de texto/cadena comunes en todos los DBMS

  • LENGTH() o CHAR_LENGTH() / LEN(): Devuelve la longitud (número de caracteres) de una cadena.
  • CONCAT(): Combina dos o más cadenas en una sola.
  • SUBSTRING() o SUBSTR(): Extrae una porción de una cadena, especificando la posición inicial y, opcionalmente, la longitud.
  • UPPER(): Convierte todos los caracteres de una cadena a mayúsculas.
  • LOWER(): Convierte todos los caracteres de una cadena a minúsculas.
  • TRIM(): Elimina los espacios en blanco (u otros caracteres especificados) del principio y/o final de una cadena.
  • LTRIM(): Elimina los espacios en blanco iniciales.
  • RTRIM(): Elimina los espacios en blanco finales.
  • REPLACE(): Reemplaza todas las ocurrencias de una subcadena por otra subcadena dentro de una cadena dada.
  • POSITION() (o similar como INSTR() / CHARINDEX()): Devuelve la posición de la primera ocurrencia de una subcadena dentro de una cadena. 

Funciones exclusivas o destacadas de PostgreSQL

Aunque la mayoría de las funciones básicas están estandarizadas, PostgreSQL ofrece funciones y operadores potentes y específicos, especialmente en el manejo de expresiones regulares y búsqueda de texto avanzado: 

  • Operador de concatenación ||: PostgreSQL, al igual que Oracle, admite el uso del operador || para concatenar cadenas, lo cual es muy utilizado y a menudo más limpio que la sintaxis de función CONCAT() en otros sistemas.
  • INITCAP(): Convierte la primera letra de cada palabra en mayúscula y el resto en minúscula. Esta función no está disponible de forma nativa en todos los demás DBMS principales (por ejemplo, SQL Server requiere funciones definidas por el usuario o procedimientos almacenados para lograr esto).
  • SPLIT_PART(): Divide una cadena en partes utilizando un delimitador específico y devuelve la parte en la posición especificada. Es muy útil para tareas de análisis de datos.
  • Funciones y operadores de búsqueda de texto completo (tsquery, tsvector): PostgreSQL tiene un soporte nativo y robusto para la búsqueda de texto completo con tipos de datos e índices especializados que van mucho más allá de las operaciones básicas LIKE o expresiones regulares.
  • Soporte nativo avanzado para Expresiones Regulares: PostgreSQL ofrece una gama de operadores (~, ~*, !~, !~*) y funciones específicas (REGEXP_REPLACE, REGEXP_MATCHES, REGEXP_SPLIT_TO_ARRAY) para trabajar con expresiones regulares de manera extensa, que son más potentes que las funciones de expresiones regulares básicas en otros sistemas.
  • Tipo de datos TEXT: Aunque no es una función, PostgreSQL trata a TEXT como un tipo de dato nativo de primera clase (no estándar SQL, pero común), y la mayoría de sus funciones de cadena operan de forma nativa con él, a diferencia de algunos otros DBMS que se centran más en VARCHAR

Ejemplo: Estandarizar nombres y correos

SELECT 
    TRIM(cliente_nombre) AS nombre_limpio, -- Quita espacios al inicio/final
    UPPER(cliente_nombre) AS nombre_mayusculas,
    LOWER(cliente_email) AS email_normalizado,
    LENGTH(TRIM(cliente_nombre)) AS longitud_nombre,
    CONCAT('Cliente: ', TRIM(cliente_nombre)) AS etiqueta_cliente
FROM ventas;

Funciones Numéricas Integradas en Todos los SGBD

Los sistemas de bases de datos como PostgreSQL, MySQL, Oracle y SQL Server implementan un conjunto básico y esencial de funciones numéricas y de agregación que cumplen con los estándares SQL (específicamente SQL92 o SQL:1999). 

  • Funcioens de agregación: AVG(), COUNT(), MAX(), MIN(), SUM(): Calculan un único resultado a partir de un conjunto de filas.
  • ABS(): Devuelve el valor absoluto de un número.
  • ROUND(): Redondea un número al entero más cercano o a un número específico de decimales.
  • POWER(), SQRT(): Calcula la potencia o la raíz cuadrada de un valor.
  • SIGN(): Devuelve el signo del número (positivo, negativo o cero).
  • MOD(): Devuelve el resto de una división.

Funciones Numéricas Exclusivas o Particulares de PostgreSQL

PostgreSQL es conocido por su fuerte cumplimiento de estándares y su capacidad de ampliación, lo que le permite ofrecer funciones y tipos de datos que no están disponibles de forma nativa o tienen una sintaxis diferente en otros SGBD. 

  • Tipos de Rango (numrange, int4range, int8range): PostgreSQL permite la representación nativa y el trabajo con intervalos de valores numéricos, lo cual es una característica potente y poco común en otros sistemas.
  • Funciones de Serialización/Conversión Específicas: Funciones como TO_NUMBER() están integradas para convertir texto a números utilizando formatos específicos, lo cual puede variar sintácticamente en otros SGBD.
  • Funciones Geoespaciales (mediante PostGIS): Aunque no son funciones numéricas puramente integradas en el núcleo, la extensión PostGIS añade una gama muy amplia de funciones espaciales y numéricas para datos geográficos que son un punto fuerte de PostgreSQL.
  • Soporte Extendido para Precisión Arbitraria: PostgreSQL maneja el tipo NUMERIC con precisión arbitraria de forma muy robusta y eficiente, lo que se refleja en sus operaciones matemáticas.
  • Funciones Avanzadas de Ventana: Aunque muchos SGBD modernos admiten funciones de ventana, PostgreSQL tiene un soporte muy completo y avanzado, incluyendo funciones como ROW_NUMBER(), que es útil para asignar numeración secuencial a las filas en un conjunto de resultados.
  • Lenguaje Procedimental PL/pgSQL: La capacidad de crear funciones numéricas personalizadas complejas utilizando su propio lenguaje de procedimiento es una característica clave, a diferencia de extensiones propietarias como T-SQL en SQL Server. 

Ejemplo: Cálculo de impuestos y descuentos. Calcularemos el subtotal, el monto del descuento y el total final (IVA 16%).

SELECT 
    id_venta,
    (cantidad * 100) / 100.0 AS cantidad_decimal, -- Forzar decimal
    ROUND(precio_unitario * cantidad, 2) AS subtotal_bruto,
    ROUND((precio_unitario * cantidad) * (descuento_porcentaje / 100), 2) AS monto_descuento,
    ROUND(((precio_unitario * cantidad) * (1 - descuento_porcentaje / 100)) * 1.16, 2) AS total_neto_iva
FROM ventas v
JOIN productos p ON v.id_producto = p.id_producto;

Funciones Estándar (Integradas en la mayoría de los SGBD)

Los SGBD compatibles con SQL, incluyendo PostgreSQL, SQL Server, MySQL y Oracle, generalmente soportan las siguientes funciones y capacidades estándar o equivalentes: 

  • Obtener fecha y hora actual: Funciones para recuperar la fecha y hora del sistema en el momento de la ejecución.
    • CURRENT_DATE: Devuelve solo la fecha actual.
    • CURRENT_TIME: Devuelve solo la hora actual.
    • CURRENT_TIMESTAMP: Devuelve la fecha y hora actual, a menudo con zona horaria.
  • Aritmética de fechas básica: La capacidad de calcular la diferencia entre dos fechas, resultando en un intervalo (por ejemplo, en días).
  • Extracción de partes de fecha/hora: Aunque la sintaxis puede variar, todos permiten extraer componentes como el año, mes, día, hora, minuto o segundo de un valor de fecha/hora. 

Funciones Exclusivas o Potenciadas en PostgreSQL

PostgreSQL se distingue por su robusto manejo de fechas y horas, que incluye tipos de datos avanzados como INTERVAL y funciones especializadas que no son estándar en todos los demás sistemas:

  • EXTRACT(unidad FROM fuente): Esta es una función SQL estándar, pero en PostgreSQL es muy versátil, permitiendo extraer una amplia gama de unidades como century, dayofweek (DOW), dayofyear (DOY), week, etc., de un valor de fecha/hora.
  • AGE(timestamp, timestamp) o AGE(timestamp): Calcula la “edad” o el intervalo entre dos marcas de tiempo (o entre una marca de tiempo y la actual), devolviendo el resultado en un formato detallado de años, meses y días.
  • Manejo de Zonas Horarias (TIMESTAMPTZ): PostgreSQL tiene un manejo nativo y transparente de zonas horarias, almacenando los datos en UTC y convirtiéndolos a la zona horaria del cliente automáticamente, lo cual es más sofisticado que en otros SGBD.
  • Operadores de Intervalo (-, +): La capacidad de restar directamente dos fechas para obtener un tipo de dato INTERVAL, que luego puede ser manipulado con operadores aritméticos de forma intuitiva.
  • Funciones de generación de series: Funciones como GENERATE_SERIES() se pueden usar para generar una serie de fechas o marcas de tiempo a intervalos regulares, lo cual es muy útil para informes y análisis de series temporales.
  • TIMEZONE(zone, timestamp): Una función específica para convertir marcas de tiempo entre diferentes zonas horarias.

Ejemplo: Antigüedad y periodos

SELECT 
    id_venta,
    fecha_venta,
    CURRENT_DATE AS hoy,
    AGE(fecha_venta) AS tiempo_transcurrido, -- Devuelve años, meses, días
    EXTRACT(YEAR FROM fecha_venta) AS anio_venta,
    EXTRACT(MONTH FROM fecha_venta) AS mes_venta,
    fecha_venta + INTERVAL '15 days' AS fecha_limite_devolucion
FROM ventas;

Queries y Funciones de Agregación

Las funciones de agregación (SUM, AVG, COUNT, MIN, MAX) colapsan múltiples filas en un solo resultado. Para que tengan sentido con campos calculados, usamos el GROUP BY. El comportamiento del resultado generado por este tipo de queries es muy similar al uso de tablas dinámicas en herramientas de hoja de cálculo.

Las funciones de agregación esenciales que se encuentran en todos los SGBD, como MySQL, SQL Server y PostgreSQL, debido a que forman parte del estándar SQL, son: 

  • COUNT(): Cuenta el número de filas o valores no nulos en un conjunto de registros.
  • SUM(): Calcula la suma total de valores numéricos en un conjunto de datos.
  • AVG(): Calcula el promedio (media aritmética) de un conjunto de valores numéricos.
  • MIN(): Encuentra el valor mínimo en un conjunto de datos (numérico, cadena o fecha/hora).
  • MAX(): Encuentra el valor máximo en un conjunto de datos (numérico, cadena o fecha/hora). 

Estas funciones son universales y se utilizan con la cláusula GROUP BY para realizar cálculos por grupo, o sobre toda la tabla si no se especifica dicha cláusula. 

Funciones de agregación exclusivas o especializadas de PostgreSQL

PostgreSQL extiende el estándar SQL con numerosas funciones de agregación avanzadas y específicas que no están disponibles de forma nativa o tienen una implementación diferente en otros SGBD. Algunas de las más destacadas incluyen: 

  • STRING_AGG() (con variaciones en otros SGBD): Concatena expresiones de varias filas en una sola cadena, con un delimitador especificado. Aunque otros SGBD tienen funciones similares (GROUP_CONCAT en MySQL, STRING_AGG en SQL Server), la implementación y sus capacidades pueden variar.
  • Agregados estadísticos y matemáticos avanzados: PostgreSQL cuenta con funciones para cálculos estadísticos más complejos, como STDDEV() (desviación estándar), VARIANCE() (varianza), CORR() (correlación), COVAR() (covarianza), entre otras.
  • Agregados para tipos de datos complejos: Soporte para agregaciones sobre tipos de datos avanzados como rangos (range types), JSON nativo (jsonb_agg, json_object_agg) y tipos geométricos, lo cual es menos común en otros SGBD.
  • Funciones de ventana (Window Functions) extendidas: Si bien las funciones de ventana básicas (ROW_NUMBER(), RANK(), etc.) y el uso de agregados como funciones de ventana (SUM() OVER (...)) son parte del estándar SQL moderno, PostgreSQL ofrece una implementación robusta y características avanzadas en su uso que superan a otros sistemas.
  • Capacidad de crear funciones agregadas definidas por el usuario: PostgreSQL permite a los usuarios definir sus propias funciones de agregación personalizadas desde cero, lo que proporciona una flexibilidad significativa para necesidades analíticas específicas. 

Reporte de Rendimiento por Categoría

Ejemplo: Queremos saber cuánto dinero real (ya con descuento) ha generado cada categoría.

SELECT 
    p.categoria,
    COUNT(v.id_venta) AS total_transacciones,
    SUM(v.cantidad) AS unidades_vendidas,
    ROUND(AVG(p.precio_unitario), 2) AS precio_promedio_prod,
    ROUND(SUM((v.cantidad * p.precio_unitario) * (1 - v.descuento_porcentaje/100)), 2) AS ingresos_reales_totales
FROM productos p
LEFT JOIN ventas v ON p.id_producto = v.id_producto
GROUP BY p.categoria
HAVING SUM(v.cantidad) > 0 -- Solo categorías que realmente han vendido algo
ORDER BY ingresos_reales_totales DESC;