miércoles, 1 de junio de 2016

Función: Días para tu Cumpleaños.

Objetivos: 
•Ver el uso de algunas funciones de fecha en PL/SQL, para con ellas crear una(función, trigger, procedimiento...) que cumpla cierto requerimiento .
•Mas que nada, entretenerme un poco.

Con frecuencia vemos programas/software que determinan el tiempo que falta para tu próximo cumpleaños, algunos te dan hasta detalles como: las horas, minutos y segundos que restan, así como también el tiempo que has vivido en días, horas o minutos. A mi me paso por la mente realizar algo parecido(con días), pero en PL/SQL.

Nota: No doy muchas explicaciones ya que las funciones que uso están explicadas en publicaciones anteriores.
Por defecto la base de datos ORACLE muestra las fechas en formato: 'DD-MM-RR HH:MI:SS' pero esto puede cambiarse con ALTER SESSION SET NLS_DATE_FORMAT='MM/DD/YYYY';
Para lograr que el siguiente SCRIPT tenga los resultados esperados, el formato de NLS_DATE_FORMAT debe estar en este orden: DD/MM/YYYY o DD-MM-YYYY.
Para ver el actual formato de tu session usa: SELECT parameter, value FROM nls_session_parameters;
_____________________________________________________________________________________

CREATE OR REPLACE FUNCTION DAYS_TO_BIRTHDAY(P_UR_BIRTH IN VARCHAR2)
    RETURN VARCHAR2
AS --Declaro P_UR_BIRTH VARCHAR2 para así poder mostrar errores si no introducen una fecha validad...
    CURSOR C_DAY_THIS_YEAR(P_DATE IN DATE) IS
        SELECT TO_DATE(EXTRACT(DAY FROM P_DATE)
            ||'/'||EXTRACT(MONTH FROM P_DATE)
            ||'/'||EXTRACT(YEAR FROM SYSDATE),'DD/MM/YYYY')-TRUNC(SYSDATE)
        FROM DUAL;
    ---
    CURSOR C_DAY_NEXT_YEAR(P_DATE IN DATE) IS
        SELECT TO_DATE(EXTRACT(DAY FROM P_DATE)
            ||'/'||EXTRACT(MONTH FROM P_DATE)
            ||'/'||EXTRACT(YEAR FROM ADD_MONTHS(SYSDATE,12)),'DD/MM/YYYY')-TRUNC(SYSDATE)
        FROM DUAL;
     ---
    V_MONTH NUMBER(2);
    V_DAY V_MONTH%TYPE;
    V_DAYS NUMBER(3);
    V_UR_BIRTH DATE;
BEGIN
    V_UR_BIRTH := TO_DATE(P_UR_BIRTH,'DD/MM/YYYY');
    V_MONTH := EXTRACT(MONTH FROM V_UR_BIRTH);
    V_DAY := EXTRACT(DAY FROM V_UR_BIRTH);
 
    IF V_MONTH > EXTRACT(MONTH FROM SYSDATE) THEN
        OPEN C_DAY_THIS_YEAR(V_UR_BIRTH);
        FETCH C_DAY_THIS_YEAR INTO V_DAYS;
        CLOSE C_DAY_THIS_YEAR;
        RETURN 'Faltan '||V_DAYS||' Días para tu cumpleaños';
 
    ELSIF V_MONTH = EXTRACT(MONTH FROM SYSDATE) THEN
        IF V_DAY > EXTRACT(DAY FROM SYSDATE) THEN
            OPEN C_DAY_THIS_YEAR(V_UR_BIRTH);
            FETCH C_DAY_THIS_YEAR INTO V_DAYS;
            CLOSE C_DAY_THIS_YEAR;
            RETURN 'Faltan '||V_DAYS||' Días para tu cumpleaños';
        ELSIF V_DAY = EXTRACT(DAY FROM SYSDATE) THEN
            RETURN '!_$_!Happy Birth Day to You!_$_!';
        ELSE
            OPEN C_DAY_NEXT_YEAR(V_UR_BIRTH);
            FETCH C_DAY_NEXT_YEAR INTO V_DAYS;
            CLOSE C_DAY_NEXT_YEAR;
            RETURN 'Faltan '||V_DAYS||' Días para tu cumpleaños';    
        END IF;
    ELSE 
        OPEN C_DAY_NEXT_YEAR(V_UR_BIRTH);
        FETCH C_DAY_NEXT_YEAR INTO V_DAYS;
        CLOSE C_DAY_NEXT_YEAR;
        RETURN 'Faltan '||V_DAYS||' Días para tu cumpleaños';
    END IF;

    EXCEPTION
        WHEN OTHERS THEN
            RETURN 'Formato de fecha Valido: Día/Mes/Año, Eje: 14/02/1993';
END;
/
SHOW ERROR-- Muestra errores de sintaxis al momento de Compilar.
/* Por supuesto esta función podría optimizarse mucho mas,  pero como el fin es de enseñanza, asumiremos que es cumple el requerimiento deseado.
*/
_____________________________________________________________________________________
Usando dicha Función: 
---
SELECT 
    HIRE_DATE AS "FECHA DE NACIMIENTO",
    SYSDATE AS HOY,
    DAYS_TO_BIRTHDAY(HIRE_DATE) AS "Mi Cumple"
FROM HR.EMPLOYEES;
/* En el ejemplo anterior se muestra el HIRE_DATE(asumimos que es la fecha de nacimiento del empleado), la fecha actual y los días que faltan para su cumpleaños, usando Nuestra función.
*/
---
SELECT 
    DAYS_TO_BIRTHDAY(SYSDATEAS "GOOD_1",
    DAYS_TO_BIRTHDAY('12-09-2000') AS "GOOD_2",
    DAYS_TO_BIRTHDAY(5) AS "BAD_1",
    DAYS_TO_BIRTHDAY('SAF') AS "BAD_2"
FROM DUAL;
/* En este ejemplo usamos la nuestra función pasandole la fecha actual, luego una cadena de caracteres con el formato valido de una fecha, luego le pasamos un numero entero y una cadena de caracteres no valida(las dos ultimas columnas mostrarían un mensaje de advertencia al usuario).
*/