sábado, 13 de julio de 2013

Creación de bucles basados en rango fechas (macros SAS)

Es habitual encontrarse la necesidad de ejecutar determinado proceso para un determinado rango de fechas. Para ello es muy útil el uso de macros de SAS que incluyan estructuras iterativas que nos permitan ejecutar un determinado código para un rango determinado de fechas. En el ejemplo que se muestra a continuación se muestra el esqueleto de una macro que permite ejecutar un código para un determinado rango de meses, en formato yyyymm.




%macro recorrer_meses(mes_ini, mes_fin);


      data _null_;


      f_ini=input(PUT(&mes_ini.01,8.),yymmdd8.);
      f_fin=input(PUT(&mes_fin.01,8.),yymmdd8.);
      format f_ini f_fin  yymmddn8.;
      dif=intck('month',f_ini,f_fin);
      call symput('num_meses',dif);
      run;


      %do n=0 %to &num_meses.;
                      %let mes=%sysfunc(intnx(month,%SYSFUNC(INPUTN(&mes_ini.01,YYMMDD8.)),%EVAL(+&n)),yymmn6.);


            %put Procesando  mes: &mes;


             /* INCLUIR CODIGO A EJECUTAR PARA CADA ITERACION */
    


      %end; 


%mend;


/* Ejemplo llamada a la macro */


%recorrer_meses(201201, 201307);

6 comentarios:

  1. Hola,
    siguiendo tu código, me crea una tabla por mes, pero como verás en el proc sql, en where, t1.fecha he puesto el rango total y sale el mismo resultado en todas las tablas. Lo que quiero es que salga el resultado de cada mes en su tabla correspondiente, pero creo que en el bucle habría que poner la fecha inicial y final de cada mes para que lo coja

    Agradacería tus comentarios

    Gracias y un saludo

    %macro recorrer_meses(mes_ini, mes_fin);
    data _null_;
    f_ini=input(PUT(&mes_ini.01,8.),yymmdd8.);
    f_fin=input(PUT(&mes_fin.01,8.),yymmdd8.);
    format f_ini f_fin yymmddn8.;
    dif=intck('month',f_ini,f_fin);
    call symput('num_meses',dif);
    run;

    *REALIZAMOS EL BUCLE PARA SEPARAR LA SALIDA POR MES;

    %do n=0 %to &num_meses.;
    %let mes=%sysfunc(intnx(month,%SYSFUNC(INPUTN(&mes_ini.01,YYMMDD8.)),%EVAL(+&n)),yymmn6.);


    * HACEMOS QUE PONGA QUE MES ESTA PROCESANDO;
    %put Procesando mes: &mes;



    * INCLUIMOS EL CODIGO A EJECUTAR PARA CADA ITERACION;

    proc sql;
    connect using PR25 as PR25;

    create table CABCON_&MES as select *
    from connection to PR25
    (select T1.USUARIO, T1.TERMINAL, T1.FECHA, T1.HORA, T1.TRANSACCION, T1.BASE_DATOS,
    T1.FECHA_PLOG, T1.NUM_SECUENCIA, T1.TAREA, T2.TIPO, T2.IDENTIFICADOR
    from cabcon t1
    inner join idecon t2 on
    (t1.fecha = t2.fecha and
    t1.base_datos = t2.base_datos and
    t1.fecha_plog = t2.fecha_plog and
    t1.num_secuencia = t2.numero_secuen
    )
    where
    t1.fecha >= &FECHAS_min and
    t1.fecha <= &FECHAS_max and
    T2.IDENTIFICADOR like '%49331718F%'

    );

    disconnect from PR25;
    quit;



    *PROCEDIMIENTO PARA SACAR UNA TABLA POR MES ORDENADA POR FECHA;
    PROC SORT DATA=CABCON_&MES;BY fecha; RUN;

    *SALIDA DE LAS TABLAS;
    proc print data=cabcon_&MES;

    %end;

    %mend;

    *EJECUCIÓN DE LA MACRO;
    %recorrer_meses(&fechas_MIN, &fechas_MAX);

    ResponderEliminar
  2. Hola,
    En tu consulta filtras por &fechas_min y &fechas_max no haces referencia a &mes que es la variable que está cambiando en cada iteracción. Dime que es lo que quieres obtener en cada consulta, ¿los datos del mes que estás recorriendo?. Por otra parte, ten en cuenta que la macro que yo planteo recorre meses en formmato yyyymm , confirma que eso casa con las variables que usas para llamarla: &fechas_min y &fechas_max. Dame más datos y veo cómo ayudarte

    ResponderEliminar
  3. Hola,
    &fechas_min y &fechas max, es el rango que yo pido en formato yyyymm. (lo hago a través de los parámetros en SAS Enterprise Guide, pero funciona correctamente la macro)
    En el proc sql puse &mes, pero las tablas las saca vacías, porque realmente necesita es el periodo mensual en formato yyyymmdd de cada mes, inicio y fin. Es el dato que yo creo que debería ponerse en el bucle para que lo coja de ahí, como fecha inicio, y fecha final de cada (&mes).
    Lo que necesito es que en cada iteración solo ponga la información de ese mes, si no hay que salga vacía la tabla.

    Gracias por la ayuda
    Fernando

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
    2. Hola,

      Te paso un ejemplo de como se puede resolver:

      %let mes=201612;

      %let fecha_ini_mes = %sysfunc(mdy(%substr(&mes,5,2),1,%substr(&mes,1,4)));

      %let fecha_ini_mes_prox = %sysfunc(intnx(month,&fecha_ini_mes,1));


      Después utilizarlo en la condición del where de la sql

      where
      t1.fecha >= &fecha_ini_mes and
      t1.fecha < &fecha_ini_mes_prox

      Espero que te sirva. Escribeme a: formacion@datademy.es

      Eliminar