PL/PgSQL: Obtener días hábiles entre un rango de fechas
En mi trabajo nos surgió la necesidad de desarrollar un algoritmo que nos permitiese calcular y generar los días hábiles de un determinado rango de fechas. Este debía ser capaz de excluir de manera automática los días Sábado, Domingo y Festivos y retornar solo el resto de los días de lunes a viernes. El planteamiento a seguir fue el siguiente:
* Elegir la tecnología para implementar el algoritmo:
Como la base de datos institucional está en PostgreSQL, pensamos que lo mejor era apegarnos a esto y utilizar como lenguaje PL/PgSQL, el cual sin duda satisfacía cada una de nuestras necesidades para el caso y mucho mas.
* Crear una tabla que contenga los días festivos:
CREATE TABLE public.dia_festivo (
cod_dia_festivo CHARACTER(5) NOT NULL,
desc_dia_festivo CHARACTER VARYING(250) NOT NULL,
PRIMARY KEY (cod_dia_festivo)
);
* Poblar la tabla public.dia_festivo
* Crear la función
CREATE OR REPLACE FUNCTION public.get_dias_habiles(date, date) RETURNS SETOF RECORD AS
$BODY$
DECLARE
fecha_ini ALIAS FOR $1; -- Fecha Inicio
fecha_ter ALIAS FOR $2; -- Fecha Termino
sabado integer := 6; -- Dia sabado
domingo integer := 0; -- Dia domingo
BEGIN
RETURN QUERY
SELECT
CAST(to_char(fecha_ini + dias, 'DD-MM-YYYY') AS character(10)) AS fecha
FROM
generate_series(0, fecha_ter - fecha_ini) AS dias
WHERE
extract (dow FROM fecha_ini + dias) NOT IN (sabado, domingo)
AND
CAST(to_char(fecha_ini + dias, 'DD-MM') AS character(5))
NOT IN
(SELECT cod_dia_festivo FROM public.dia_festivo);
END;
$BODY$
LANGUAGE 'plpgsql';
* Llamar la función:
SELECT
fecha
FROM
public.get_dias_habiles('2009-01-01', '2009-12-31')
AS
dias_habiles(fecha character);
Creo que todo el código es practicamente autoexplicable para alguien con conocimientos de SQL, PostgreSQL y PL/PgSQL, y la idea principal de compartirlo es obtener algún feedback con algún enfoque distinto, correcciones, y por supuesto que le pueda ser de utilidad y mejore el día a quien lo necesite.
PS, Perdón por la falta de indentación pero drupal se la comió. :P
- Add new comment
- 2854 reads

Comments
Otra funcion del mismo tipo
Estimados,
No sé como ingresar un nuevo articulo al sitio, de todas maneras era para publicar otra funcion del mismo tipo. Se encuentra en la siguiente URL:
http://manuel.radiohead.cl/2009/proximo-dia-habil-en-postgresql/
Algunos feriado cambian cada
Algunos feriado cambian cada año, y tu modelo no soporta eso. De hecho si no entiendo mal en tu modelo es imposible definir correctamente la fecha del feriado de Viernes Santo para más de un año.
Lo del formateo, es malo. Los objetos en la BD no deben presuponer cómo van a ser llamados, o qué formato va a querer darle el usuario. Deben retornar los tipos más naturales posible de manera que el usuario le dé el formato que le parezca.
Respecto del tipo char(), el problema con éste es que el comportamiento que define el estándar tiene varios comportamientos que se pueden definir de "curiosos", pero no tengo intención de entrar en detalles. La alternativa correcta es usar varchar().
Que retorne un string es por
Que retorne un string es por un tema de formateo y que dia_festivo sea de tipo character(5) tiene que ver directamente con que la actualización no este amarrada a un año especifico. Lo que me dejo preocupado es lo que mencionas respecto a no usar el tipo char(), podrías contarme un poco mas al respecto ?... Cual es la alternativa correcta ?.
Saludos
tipos de dato
Es buena la idea, gracias por compartirla. Lo que yo le cambiaría es que en vez de retornar un string, retorne tipo “date”. Y la definición de la tabla dia_festivo también debería tener una fecha, no un char(5).
De paso aprovecho de comentar que el tipo char() no debería usarse nunca porque está mal definido.