MySQL provee varias funciones que se aplican a cálculos entre fechas, por ejemplo, para calcular edades u obtener partes de una fecha.
Para determinar cuántos años de edad tiene cada mascota, hay que calcular la diferencia entre el año de la fecha actual y el de la fecha de nacimiento, y luego restar 1 al resultado si el dia y mes actuales son anteriores al día y mes indicados por la fecha de nacimiento. La siguiente consulta devuelve, para cada mascota, el nombre, la fecha de nacimiento, la fecha actual, y la edad en años.
mysql> SELECT name, birth, CURDATE(), -> (YEAR(CURDATE())-YEAR(birth)) -> - (RIGHT(CURDATE(),5)<RIGHT(birth,5)) -> AS age -> FROM pet; +----------+------------+------------+------+ | name | birth | CURDATE() | age | +----------+------------+------------+------+ | Fluffy | 1993-02-04 | 2003-08-19 | 10 | | Claws | 1994-03-17 | 2003-08-19 | 9 | | Buffy | 1989-05-13 | 2003-08-19 | 14 | | Fang | 1990-08-27 | 2003-08-19 | 12 | | Bowser | 1989-08-31 | 2003-08-19 | 13 | | Chirpy | 1998-09-11 | 2003-08-19 | 4 | | Whistler | 1997-12-09 | 2003-08-19 | 5 | | Slim | 1996-04-29 | 2003-08-19 | 7 | | Puffball | 1999-03-30 | 2003-08-19 | 4 | +----------+------------+------------+------+
En el ejemplo anterior, YEAR()
trae la
parte correspondiente al año de una fecha, y
RIGHT()
trae los 5 primeros caracteres
contando desde la derecha, que representan la parte
MM-DD
de la fecha. La porción de la
expresión que compara los valores MM-DD
devuelve 1 o 0, lo cual se corresponde con la diferencia de 1
año a restar de la edad si el dia de la fecha devuelto por
CURDATE()
ocurre antes que la fecha de
nacimiento birth
. La expresión completa es
un tanto confusa para usar como encabezado, por lo que se
emplea un alias (age
)
para que el encabezado sea más comprensible.
La consulta funciona bien, pero los resultados podrían
revisarse más fácilmente si las filas se presentaran en
algún orden. Esto puede hacerse agregando la cláusula
ORDER BY name
para ordenar por nombre la
salida:
mysql> SELECT name, birth, CURDATE(), -> (YEAR(CURDATE())-YEAR(birth)) -> - (RIGHT(CURDATE(),5)<RIGHT(birth,5)) -> AS age -> FROM pet ORDER BY name; +----------+------------+------------+------+ | name | birth | CURDATE() | age | +----------+------------+------------+------+ | Bowser | 1989-08-31 | 2003-08-19 | 13 | | Buffy | 1989-05-13 | 2003-08-19 | 14 | | Chirpy | 1998-09-11 | 2003-08-19 | 4 | | Claws | 1994-03-17 | 2003-08-19 | 9 | | Fang | 1990-08-27 | 2003-08-19 | 12 | | Fluffy | 1993-02-04 | 2003-08-19 | 10 | | Puffball | 1999-03-30 | 2003-08-19 | 4 | | Slim | 1996-04-29 | 2003-08-19 | 7 | | Whistler | 1997-12-09 | 2003-08-19 | 5 | +----------+------------+------------+------+
Para ordenar la salida por edad (age
) en
lugar de por nombre (name
), solo hay que
utilizar una cláusula ORDER BY
diferente:
mysql> SELECT name, birth, CURDATE(), -> (YEAR(CURDATE())-YEAR(birth)) -> - (RIGHT(CURDATE(),5)<RIGHT(birth,5)) -> AS age -> FROM pet ORDER BY age; +----------+------------+------------+------+ | name | birth | CURDATE() | age | +----------+------------+------------+------+ | Chirpy | 1998-09-11 | 2003-08-19 | 4 | | Puffball | 1999-03-30 | 2003-08-19 | 4 | | Whistler | 1997-12-09 | 2003-08-19 | 5 | | Slim | 1996-04-29 | 2003-08-19 | 7 | | Claws | 1994-03-17 | 2003-08-19 | 9 | | Fluffy | 1993-02-04 | 2003-08-19 | 10 | | Fang | 1990-08-27 | 2003-08-19 | 12 | | Bowser | 1989-08-31 | 2003-08-19 | 13 | | Buffy | 1989-05-13 | 2003-08-19 | 14 | +----------+------------+------------+------+
Una consulta similar se utiliza para determinar la edad a la
fecha de muerte de los animales. Se determinan los animales
que han muerto verificando si el valor de la columna
death
es NULL
. Entonces,
para todos los valores no NULL
calcula la
diferencia entre las fechas de muerte
(death
) y nacimiento
(birth
):
mysql> SELECT name, birth, death, -> (YEAR(death)-YEAR(birth)) - (RIGHT(death,5)<RIGHT(birth,5)) -> AS age -> FROM pet WHERE death IS NOT NULL ORDER BY age; +--------+------------+------------+------+ | name | birth | death | age | +--------+------------+------------+------+ | Bowser | 1989-08-31 | 1995-07-29 | 5 | +--------+------------+------------+------+
La consulta utiliza la expresión death IS NOT
NULL
en lugar de death <>
NULL
porque NULL
es un valor
especial, que no puede ser comparado mediante los operadores
lógicos habituales. Este tema se trata más extensamente más
adelante. Consultar Sección 3.3.4.6, “Trabajar con valores NULL
”.
¿Qué tal si se quisiera saber qué animales cumplen años el
próximo mes? Para esta clase de cálculos, el año y el día
son irrelevantes; simplemente se desea extraer de la columna
birth
la parte correspondiente al mes.
MySQL cuenta con varias funciones para extraer partes de
fechas, como YEAR()
,
MONTH()
, y DAYOFMONTH()
.
MONTH()
es la función apropiada para este
caso. Para verla en funcionamiento, ejecute una consulta que
muestra tanto el valor de birth
como el de
MONTH(birth)
:
mysql> SELECT name, birth, MONTH(birth) FROM pet; +----------+------------+--------------+ | name | birth | MONTH(birth) | +----------+------------+--------------+ | Fluffy | 1993-02-04 | 2 | | Claws | 1994-03-17 | 3 | | Buffy | 1989-05-13 | 5 | | Fang | 1990-08-27 | 8 | | Bowser | 1989-08-31 | 8 | | Chirpy | 1998-09-11 | 9 | | Whistler | 1997-12-09 | 12 | | Slim | 1996-04-29 | 4 | | Puffball | 1999-03-30 | 3 | +----------+------------+--------------+
Encontrar los animales que cumplen años el mes siguiente es
también sencillo. Suponga que el mes actual es abril. De modo
que su número es 4
, y se buscan los
animales nacidos en Mayo (mes 5
), de esta
forma:
mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5; +-------+------------+ | name | birth | +-------+------------+ | Buffy | 1989-05-13 | +-------+------------+
Esto se complica ligeramente cuando el mes actual es
Diciembre. No se puede simplemente sumarle 1 al número del
mes (12
) y buscar animales nacidos en el
mes 13
, porque no existe tal mes. En lugar
de eso, se debe buscar por animales nacidos en Enero (mes
1
).
Se puede incluso escribir la consulta de forma que funcione
sin importar cual es el mes actual. Así, no se necesitará
indicar un mes en particular en la consulta.
DATE_ADD()
sirve para sumar un intervalo de
tiempo a una fecha dada. Si se adiciona un mes al valor de
CURDATE()
, y se extrae el mes mediante
MONTH()
, el resultado será el mes en el
que se buscarán cumpleaños:
mysql> SELECT name, birth FROM pet -> WHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));
Una manera alternativa de alcanzar el mismo resultado es sumar
1
al mes actual para obtener el mes
siguiente (después de emplear la función módulo
(MOD
) para dejar el número de mes en
0
si resultara ser 12
:
mysql> SELECT name, birth FROM pet -> WHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;
Advierta que MONTH
devuelve un número
entre 1
y 12
. Y
MOD(algun_valor,12)
devuelve un número
entre 0
y 11
. La suma
debe ser realizada después de MOD()
, en
otro caso se estaría pasando de Noviembre
(11
) a Enero (1
).
Ésta es una traducción del manual de referencia de MySQL, que puede encontrarse en dev.mysql.com. El manual de referencia original de MySQL está escrito en inglés, y esta traducción no necesariamente está tan actualizada como la versión original. Para cualquier sugerencia sobre la traducción y para señalar errores de cualquier tipo, no dude en dirigirse a mysql-es@vespito.com.