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_0modo_1modo_3
202606202607202607

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;
fechayearweek_iso
2025-12-29202601
2025-12-30202601
2025-12-31202601
2026-01-01202601
2026-01-02202601
2026-01-03202601
2026-01-04202601

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;
semanadesdehastapedidosingresos
2025512025-12-152025-12-215414800.30
2025522025-12-222025-12-285816200.40
2026012025-12-292026-01-04409800.60
2026022026-01-052026-01-115213200.50
2026032026-01-122026-01-184812100.80
2026042026-01-192026-01-255514350.20
2026052026-01-262026-01-314410800.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;
semanaanopedidosingresos
2024072024389200.50
20250720254210350.80
20260720264611189.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;
semanapedidosingresosvariacion_pct
202601286850.30NULL
2026025213200.5092.7
2026034812100.80-8.3
2026045514350.2018.6
2026055112800.40-10.8
2026064711650.30-9.0
2026074611189.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_nullfecha_invalida
NULLNULL

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_completoano_extraidosemana_extraida
20260720267

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);
periodopedidosingresos
Semana 1 de 2026286850.30
Semana 2 de 20265213200.50
Semana 3 de 20264812100.80
Semana 4 de 20265514350.20

En el siguiente articulo veremos QUARTER para obtener el trimestre.

Escrito por Eduardo Lázaro