Archive for September 27th, 2006

Una función agregada para MySQL 5 para el calculo de fechas:

Wednesday, September 27th, 2006

Me encontraba observando ve.planetalinux.org cuando me di cuenta de dos cosas:
1.- alguien habia sindicalizado mi blog sin preguntarme; que bien, es bueno saber que hay gente que te lee.
2.- hay alguien que escribio una funcion en php para un sistema de noticias, la funcion debia retornar algo como “esto fue escrito hace: 1 año, 4 meses, 2 dias, 7 horas, 4 minutos y 30 segundos”.
La funcion sonaba interesante para mi, pero no para usarla en PHP, sino por mi fiel idea que el procesamiento en bruto de los datos debe ser ejecutado por el RDBMS y no por el cliente, decidi enfrentar ese reto de lograr que mySQL me emitiera la misma informacion.

Paso 1: Crear una sentencia SQL que retorne la informacion solicitada:

SELECT CONCAT(year(curdate()) - YEAR(’2005-07-21 08:15:00′), ‘ año, ‘, month(curdate()) - month(’2005-07-21 08:15:00′), ‘ meses, ‘, day(curdate()) - day(’2005-07-21 08:15:00′), ‘ dias, ‘, abs(time_format(’2005-07-21 08:15:00′, ‘%h’) - hour(curtime())), ‘ horas, ‘, abs(time_format(’2005-07-21 08:15:00′, ‘%i’) - minute(curtime())), ‘ minutos y ‘, abs(time_format(’2005-07-21 08:15:00′, ‘%s’) - second(curtime())), ‘ segundos’) AS tiempo_transcurrido

Es una sentencia interesante, larga, pero interesante, ahora bien, si a eso lo llevamos a una funcion agregada de mySQL 5 nos queda:

Paso 2: Crear una funcion agregada para mySQL 5 llamada tiempo_transcurrido:

DELIMITER $$
DROP FUNCTION IF EXISTS `mydb`.`tiempo_transcurrido`$$
CREATE FUNCTION `mydb`.`tiempo_transcurrido` (fecha_usuario DATETIME) RETURNS VARCHAR(75)
BEGIN
DECLARE fecha_t VARCHAR(75);
DECLARE fecha DATE;
DECLARE tiempo TIME;
DECLARE anno TINYINT(2);
DECLARE mes TINYINT(2);
DECLARE dia TINYINT(2);
DECLARE hora TINYINT(2);
DECLARE minuto TINYINT(2);
DECLARE segundo TINYINT(2);
SELECT curdate() INTO fecha;
SELECT curtime() INTO tiempo;
SELECT YEAR(fecha) - YEAR(fecha_usuario) INTO anno;
SELECT MONTH(fecha) - MONTH(fecha_usuario) INTO mes;
SELECT DAY(fecha) - DAY(fecha_usuario) INTO dia;
SELECT abs(HOUR(fecha_usuario) - HOUR(tiempo)) INTO hora;
SELECT abs(MINUTE(fecha_usuario) - MINUTE(tiempo)) INTO minuto;
SELECT abs(SECOND(fecha_usuario) - SECOND(tiempo)) INTO segundo;
IF anno > 0 THEN
BEGIN
IF anno > 1 THEN
BEGIN
SELECT CONCAT(anno, ‘ años, ‘) INTO fecha_t;
END;
ELSE
BEGIN
SELECT CONCAT(anno, ‘ año, ‘) INTO fecha_t;
END;
END IF;
END;
END IF;
IF mes > 1 THEN
BEGIN
SELECT CONCAT(fecha_t, mes , ‘ meses, ‘) INTO fecha_t;
END;
ELSE
BEGIN
SELECT CONCAT(fecha_t, mes, ‘ mes, ‘) INTO fecha_t;
END;
END IF;
IF dia > 1 THEN
BEGIN
SELECT CONCAT(fecha_t, dia , ‘ dias, ‘) INTO fecha_t;
END;
ELSE
BEGIN
SELECT CONCAT(fecha_t, dia, ‘ dia, ‘) INTO fecha_t;
END;
END IF;
IF hora > 1 THEN
BEGIN
SELECT CONCAT(fecha_t, hora , ‘ horas, ‘) INTO fecha_t;
END;
ELSE
BEGIN
SELECT CONCAT(fecha_t, hora, ‘ hora, ‘) INTO fecha_t;
END;
END IF;
IF minuto > 1 THEN
BEGIN
SELECT CONCAT(fecha_t, minuto , ‘ minutos’) INTO fecha_t;
END;
ELSE
BEGIN
SELECT CONCAT(fecha_t, minuto, ‘ minuto’) INTO fecha_t;
END;
END IF;
IF segundo <> 1 THEN
BEGIN
SELECT CONCAT(fecha_t, ‘ y ‘, segundo , ‘ segundos.’) INTO fecha_t;
END;
ELSE
BEGIN
SELECT CONCAT(fecha_t, ‘ y ‘, segundo, ‘ segundo.’) INTO fecha_t;
END;
END IF;
RETURN fecha_t;
END$$
DELIMITER ;

Sip, es mas larga, pero a la final mas util, su convocatoria devuelve algo como esto:
SELECT `mydb`.`tiempo_transcurrido`(’2004-07-21 09:15:00′)
Retorna:
2 años, 2 meses, 6 dias, 7 horas, 7 minutos y 43 segundos.
(al momento que la ejecuté pues usa CURRENT_TIME (la fecha actual) como valor para el computo).

Espero esta funcion sea de utilidad no solo para lo cual fue diseñada sino para demostrar lo útil y versatil de mySQL 5 y sus procedimientos almacenados y funciones agregadas.