Fechas: date_trunc, extract y to_char
Básicodate_trunc('month', fecha) lleva cada fecha al inicio de su mes (también 'day', 'week', 'year'): sirve para agrupar por período. extract(parte FROM fecha) devuelve una parte como número (año, mes, día, hora). to_char(fecha, 'YYYY-MM') la convierte en texto con el formato que elijas.
Sintaxis
date_trunc('month', fecha)
extract(year FROM fecha)
to_char(fecha, 'YYYY-MM-DD')Ejemplo
SELECT
to_char(date_trunc('month', u.signup_at), 'YYYY-MM') AS mes,
extract(quarter FROM u.signup_at) AS trimestre,
count(*) AS altas
FROM users AS u
WHERE u.signup_at >= '2025-01-01'
AND u.signup_at < '2025-07-01'
GROUP BY date_trunc('month', u.signup_at), extract(quarter FROM u.signup_at)
ORDER BY mes;Resultado
| mes | trimestre | altas |
|---|---|---|
| 2025-01 | 1 | 278 |
| 2025-02 | 1 | 271 |
| 2025-03 | 1 | 305 |
| 2025-04 | 2 | 287 |
| 2025-05 | 2 | 313 |
| 2025-06 | 2 | 325 |
Cómo leerlo
Cada registro de usuario se lleva al primer día de su mes y se cuenta por mes. to_char muestra el mes como texto 2025-01, que es más legible que 2025-01-01 00:00:00+00. extract(quarter …) devuelve el trimestre como número. signup_at es un timestamptz (fecha y hora con zona horaria), así que el corte de mes se hace en la zona de la sesión, que en el curso es UTC.
Error común
Así no
SELECT extract(month FROM u.signup_at) AS mes, count(*) AS altas
FROM users AS u
GROUP BY extract(month FROM u.signup_at);Agrupar por extract(month …) cuando los datos abarcan más de un año. extract devuelve solo el número del mes, así que enero de 2024 y enero de 2025 caen en el mismo grupo y los totales se mezclan. Para una serie mensual usa date_trunc('month', …), que conserva el año.
En otros motores: BigQuery, SQL Server, MySQL, Oracle
BigQuery
Los argumentos van en el orden inverso: primero la fecha, después la parte, sin comillas. Para
TIMESTAMPse usaTIMESTAMP_TRUNC.DATE_TRUNC(fecha, MONTH) TIMESTAMP_TRUNC(fecha_hora, MONTH) FORMAT_DATE('%Y-%m', fecha)SQL Server
DATEPARTequivale aextract.DATETRUNCexiste desde SQL Server 2022; en versiones anteriores se arma conDATEFROMPARTS(YEAR(fecha), MONTH(fecha), 1).DATEPART(month, fecha) DATETRUNC(month, fecha) -- SQL Server 2022 o posterior FORMAT(fecha, 'yyyy-MM')MySQL
No tiene
date_trunc. Para agrupar por mes suele usarseDATE_FORMATcon el formato del período;EXTRACT(MONTH FROM fecha)funciona igual que en PostgreSQL.DATE_FORMAT(fecha, '%Y-%m')Oracle
Trunca con
TRUNC(fecha, 'MM').TO_CHARyEXTRACTse escriben como en PostgreSQL.TRUNC(fecha, 'MM') TO_CHAR(fecha, 'YYYY-MM')
Estos fragmentos no se ejecutan en el curso: se muestran como referencia de cada motor.