YEARWEEK
La funcion YEARWEEK() devuelve un entero que combina el ano y el numero de semana en formato YYYYWW. Mientras que usar YEAR() y WEEK() por separado puede generar ambiguedades en los limites entre anos (la semana 1 de 2026 podria confundirse con la semana 1 de 2025), YEARWEEK() produce un identificador unico e inequivoco para cada semana. Es la funcion ideal para agrupar datos en reportes semanales que abarcan multiples anos.
Sintaxis
YEARWEEK(fecha)
YEARWEEK(fecha, modo)El parametro fecha acepta valores de tipo DATE o DATETIME. El parametro modo es opcional y funciona exactamente igual que en WEEK(), aceptando valores del 0 al 7 que determinan cuando empieza la semana y como se define la primera semana del ano. Si omites el modo, MySQL usa el valor por defecto 0.
El resultado es un entero de 6 digitos. Por ejemplo, 202607 significa la semana 7 del ano 2026. Es importante notar que YEARWEEK() puede devolver un ano diferente al de la fecha de entrada. Si el 31 de diciembre de 2025 pertenece a la semana 1 de 2026 segun el modo seleccionado, la funcion devolvera 202601, no 202553.
Comportamiento basico
Para obtener el ano-semana de una fecha:
SELECT YEARWEEK('2026-02-14') AS ano_semana;| ano_semana |
|---|
| 202606 |
El resultado 202606 indica que el 14 de febrero de 2026 pertenece a la semana 6 del ano 2026 (usando modo 0 por defecto, donde la semana empieza en domingo).
Comparemos el resultado con diferentes modos:
SELECT
YEARWEEK('2026-02-14', 0) AS modo_0,
YEARWEEK('2026-02-14', 1) AS modo_1,
YEARWEEK('2026-02-14', 3) AS modo_3;| modo_0 | modo_1 | modo_3 |
|---|---|---|
| 202606 | 202607 | 202607 |
La diferencia se debe a que el modo 0 empieza la semana en domingo, mientras que los modos 1 y 3 la empiezan en lunes. Esto afecta a que numero de semana se asigna segun el dia.
Observa como se comporta YEARWEEK() en el limite entre anos:
SELECT
fecha,
YEARWEEK(fecha, 3) AS yearweek_iso
FROM (
SELECT '2025-12-29' AS fecha
UNION SELECT '2025-12-30'
UNION SELECT '2025-12-31'
UNION SELECT '2026-01-01'
UNION SELECT '2026-01-02'
UNION SELECT '2026-01-03'
UNION SELECT '2026-01-04'
) fechas
ORDER BY fecha;| fecha | yearweek_iso |
|---|---|
| 2025-12-29 | 202601 |
| 2025-12-30 | 202601 |
| 2025-12-31 | 202601 |
| 2026-01-01 | 202601 |
| 2026-01-02 | 202601 |
| 2026-01-03 | 202601 |
| 2026-01-04 | 202601 |
Con el modo ISO (3), los ultimos dias de diciembre de 2025 pertenecen a la semana 1 de 2026. La funcion YEARWEEK() refleja esto correctamente devolviendo 202601, no 202553. Si usaras CONCAT(YEAR(fecha), WEEK(fecha, 3)) en su lugar, obtendrias 202501 para esas fechas de diciembre, lo cual seria incorrecto. Esta es la principal ventaja de YEARWEEK() frente a combinar YEAR() y WEEK() manualmente.
Caso practico: reporte semanal de ventas
YEARWEEK() simplifica la generacion de reportes semanales porque te da un identificador unico por semana sin necesidad de agrupar por dos columnas:
SELECT
YEARWEEK(fecha_pedido, 1) AS semana,
MIN(fecha_pedido) AS desde,
MAX(fecha_pedido) AS hasta,
COUNT(*) AS pedidos,
ROUND(SUM(total), 2) AS ingresos
FROM pedidos
WHERE fecha_pedido BETWEEN '2025-12-15' AND '2026-01-31'
GROUP BY YEARWEEK(fecha_pedido, 1)
ORDER BY semana;| semana | desde | hasta | pedidos | ingresos |
|---|---|---|---|---|
| 202551 | 2025-12-15 | 2025-12-21 | 54 | 14800.30 |
| 202552 | 2025-12-22 | 2025-12-28 | 58 | 16200.40 |
| 202601 | 2025-12-29 | 2026-01-04 | 40 | 9800.60 |
| 202602 | 2026-01-05 | 2026-01-11 | 52 | 13200.50 |
| 202603 | 2026-01-12 | 2026-01-18 | 48 | 12100.80 |
| 202604 | 2026-01-19 | 2026-01-25 | 55 | 14350.20 |
| 202605 | 2026-01-26 | 2026-01-31 | 44 | 10800.40 |
La transicion entre 2025 y 2026 se maneja correctamente. La semana 202601 incluye dias de ambos anos, y el reporte fluye sin discontinuidades. Si hubieras agrupado por YEAR() y WEEK() por separado, esa semana de transicion apareceria dividida en dos filas.
Caso practico: comparar la misma semana en anos diferentes
Para comparar el rendimiento de una semana especifica entre anos:
SELECT
YEARWEEK(fecha_pedido, 1) AS semana,
LEFT(YEARWEEK(fecha_pedido, 1), 4) AS ano,
COUNT(*) AS pedidos,
ROUND(SUM(total), 2) AS ingresos
FROM pedidos
WHERE RIGHT(YEARWEEK(fecha_pedido, 1), 2) = RIGHT(YEARWEEK(CURDATE(), 1), 2)
AND YEAR(fecha_pedido) IN (2024, 2025, 2026)
GROUP BY YEARWEEK(fecha_pedido, 1)
ORDER BY semana;| semana | ano | pedidos | ingresos |
|---|---|---|---|
| 202407 | 2024 | 38 | 9200.50 |
| 202507 | 2025 | 42 | 10350.80 |
| 202607 | 2026 | 46 | 11189.00 |
Este reporte muestra la evolucion de la semana 7 a lo largo de tres anos. Facilita ver si el negocio esta creciendo en terminos comparables semana a semana.
Caso practico: tabla de resumen semanal con variacion
Un reporte mas elaborado puede incluir la variacion respecto a la semana anterior:
SELECT
s.semana,
s.pedidos,
s.ingresos,
ROUND(
(s.ingresos - LAG(s.ingresos) OVER (ORDER BY s.semana)) /
LAG(s.ingresos) OVER (ORDER BY s.semana) * 100,
1) AS variacion_pct
FROM (
SELECT
YEARWEEK(fecha_pedido, 1) AS semana,
COUNT(*) AS pedidos,
ROUND(SUM(total), 2) AS ingresos
FROM pedidos
WHERE fecha_pedido BETWEEN '2026-01-01' AND '2026-02-14'
GROUP BY YEARWEEK(fecha_pedido, 1)
) s
ORDER BY s.semana;| semana | pedidos | ingresos | variacion_pct |
|---|---|---|---|
| 202601 | 28 | 6850.30 | NULL |
| 202602 | 52 | 13200.50 | 92.7 |
| 202603 | 48 | 12100.80 | -8.3 |
| 202604 | 55 | 14350.20 | 18.6 |
| 202605 | 51 | 12800.40 | -10.8 |
| 202606 | 47 | 11650.30 | -9.0 |
| 202607 | 46 | 11189.00 | -4.0 |
La funcion de ventana LAG() accede al valor de la fila anterior, lo que permite calcular la variacion porcentual semana a semana. La primera semana muestra NULL porque no tiene semana anterior con la que compararse.
Manejo de NULL
YEARWEEK() devuelve NULL cuando recibe una fecha nula o invalida:
SELECT
YEARWEEK(NULL) AS resultado_null,
YEARWEEK('2025-02-30') AS fecha_invalida;| resultado_null | fecha_invalida |
|---|---|
| NULL | NULL |
En contextos donde necesitas un valor por defecto, usa COALESCE:
SELECT
id,
COALESCE(YEARWEEK(fecha_envio, 1), 0) AS semana_envio
FROM pedidos
WHERE fecha_pedido BETWEEN '2026-02-01' AND '2026-02-14';Los pedidos que aun no se han enviado (fecha_envio es NULL) mostraran 0 en lugar de NULL, lo que facilita el filtrado posterior.
Combinacion con otras funciones
Para descomponer el resultado de YEARWEEK() en sus componentes:
SELECT
YEARWEEK('2026-02-14', 1) AS yearweek_completo,
YEARWEEK('2026-02-14', 1) DIV 100 AS ano_extraido,
YEARWEEK('2026-02-14', 1) MOD 100 AS semana_extraida;| yearweek_completo | ano_extraido | semana_extraida |
|---|---|---|
| 202607 | 2026 | 7 |
La division entera por 100 extrae el ano, y el modulo 100 extrae la semana. Esto es util cuando necesitas trabajar con los componentes por separado despues de haberlos almacenado como un solo valor.
Tambien puedes construir etiquetas legibles para presentar en reportes:
SELECT
CONCAT(
'Semana ',
YEARWEEK(fecha_pedido, 1) MOD 100,
' de ',
YEARWEEK(fecha_pedido, 1) DIV 100
) AS periodo,
COUNT(*) AS pedidos,
ROUND(SUM(total), 2) AS ingresos
FROM pedidos
WHERE fecha_pedido BETWEEN '2026-01-01' AND '2026-01-31'
GROUP BY YEARWEEK(fecha_pedido, 1)
ORDER BY YEARWEEK(fecha_pedido, 1);| periodo | pedidos | ingresos |
|---|---|---|
| Semana 1 de 2026 | 28 | 6850.30 |
| Semana 2 de 2026 | 52 | 13200.50 |
| Semana 3 de 2026 | 48 | 12100.80 |
| Semana 4 de 2026 | 55 | 14350.20 |
En el siguiente articulo veremos QUARTER para obtener el trimestre.
Escrito por Eduardo Lázaro
