2010-11-11 11 views
5

Tengo 2 macros debajo que estoy tratando de ejecutar 1 tras otro como un ciclo utilizando una tabla de metadatos y el comando ejecutar llamada en un paso de datos.Problema de variables macro al usar ejecutar llamada

macro% TWO requiere la variable global & names_agg. se supone que debe ser creado en macro% ONE. Sin embargo, en el código siguiente, & names_agg está en blanco la primera vez que lo ejecuto. Si lo ejecuto nuevamente, solo mantendrá el valor de la última vez que se ejecutó.

La idea es que cada vez que se ejecute% ONE, un nuevo & names_agg. es creado.

¿Qué estoy haciendo mal?

Gracias

%macro ONE(condition); 
%global names_agg; 
%let names_agg = ; 

proc sql; 
    select 
     cats(name,"_agg"), 
    into 
     :names_agg separated by " ", 
    from dataset 
    where condition = "&condition." 
    ; 
quit; 
%mend; 

%macro TWO(name_OT); 

data &name_OT.; 
    set &names_agg.; 
run; 

%mend; 

data _null_; 
    length code $32767; 
    set meta_table; 
    code = "%ONE(" || cats(condition) || "); %TWO(" || cats(Name_OT) || ");"; 
    call execute(code); 
run; 

Lo siento por el registro desordenado, este es el código real. El problema es con NAMES_AGG_A -B y _C sin resolviendo correctamente

871 data test; 
872 length code $32767; 
873 set c.new_name_OT (obs=1); 
874 code = '%OT_Append(' || cats(portfolio) || ',' || cats(scorecard) || ',' || 
874! cats(event_table) || ',' || 
875   cats(scorecard_type) || ',' || cats(obs_period) || ',' || cats(outcome_period) || 
875! ',' || cats(x_var) || 
876   ',' || cats(y_var) || ',' || cats(use) || ',' || cats(condition) || '); %put 
876! &names_agg_a.; %OT_Append2(' || cats(Name_OT) || ');'; 
877 call execute(code); 
878 run; 

MLOGIC(OT_APPEND): Beginning execution. 
MLOGIC(OT_APPEND): Parameter PORTFOLIO has value MTG 
MLOGIC(OT_APPEND): Parameter SCORECARD has value A 
MLOGIC(OT_APPEND): Parameter EVENT_TABLE has value event_table_name 
MLOGIC(OT_APPEND): Parameter SCORECARD_TYPE has value Application 
MLOGIC(OT_APPEND): Parameter OBS_PERIOD has value 1 
MLOGIC(OT_APPEND): Parameter OUTCOME_PERIOD has value 18 
MLOGIC(OT_APPEND): Parameter X_VAR has value PI 
MLOGIC(OT_APPEND): Parameter Y_VAR has value GB_Odds 
MLOGIC(OT_APPEND): Parameter USE has value Development 
MLOGIC(OT_APPEND): Parameter CONDITION has value 
MLOGIC(OT_APPEND): %LET (variable name is NAMES_AGG_A) 
MLOGIC(OT_APPEND): %LET (variable name is NAMES_AGG_B) 
MLOGIC(OT_APPEND): %LET (variable name is NAMES_AGG_C) 
MPRINT(OT_APPEND): proc sql; 
SYMBOLGEN: Macro variable PORTFOLIO resolves to MTG 
SYMBOLGEN: Macro variable SCORECARD resolves to A 
SYMBOLGEN: Macro variable EVENT_TABLE resolves to event_table_name 
SYMBOLGEN: Macro variable SCORECARD_TYPE resolves to Application 
SYMBOLGEN: Macro variable OBS_PERIOD resolves to 1 
SYMBOLGEN: Macro variable OUTCOME_PERIOD resolves to 18 
SYMBOLGEN: Macro variable X_VAR resolves to PI 
SYMBOLGEN: Macro variable Y_VAR resolves to GB_Odds 
SYMBOLGEN: Macro variable USE resolves to Development 
SYMBOLGEN: Macro variable CONDITION resolves to 
MPRINT(OT_APPEND): select cats("c.",name,"_agg_a"), cats("c.",name,"_agg_b"), 
cats("c.",name,"_agg_c") into :names_agg_a separated by " ", :names_agg_b separated by " ", 
:names_agg_c separated by " " from c.datasets_pit where portfolio = "MTG" and scorecard = "A" 
and event_table = "event_table_name" and scorecard_type = "Application" and obs_period = 1 and 
outcome_period = 18 and x_var = "PI" and y_var = "GB_Odds" and use = "Development" and 
condition = "" ; 
MPRINT(OT_APPEND): quit; 
MLOGIC(OT_APPEND): Ending execution. 
SYMBOLGEN: Macro variable NAMES_AGG_A resolves to 

En esencia, el problema es que aquí, la declaración pone por encima de la llamada ejecutar programas que NAMES_AGG_A resuelve nada.

NOTE: DATA statement used (Total process time): 
     real time   0.00 seconds 
     cpu time   0.00 seconds 

MLOGIC(OT_APPEND2): Beginning execution. 
MLOGIC(OT_APPEND2): Parameter NAME_OT2 has value MTG_Dev_OT_1 
SYMBOLGEN: Macro variable NAME_OT2 resolves to MTG_Dev_OT_1 
MPRINT(OT_APPEND2): data c.MTG_Dev_OT_1_ODDS; 
SYMBOLGEN: Macro variable NAMES_AGG_A resolves to 
MPRINT(OT_APPEND2): set ; 
MPRINT(OT_APPEND2): run; 
SYMBOLGEN: Macro variable NAME_OT2 resolves to MTG_Dev_OT_1 
MPRINT(OT_APPEND2): data c.MTG_Dev_OT_1_GINI; 
SYMBOLGEN: Macro variable NAMES_AGG_B resolves to 
MPRINT(OT_APPEND2): set ; 
MPRINT(OT_APPEND2): run; 
SYMBOLGEN: Macro variable NAME_OT2 resolves to MTG_Dev_OT_1 
MPRINT(OT_APPEND2): data c.MTG_Dev_OT_1_DIST; 
SYMBOLGEN: Macro variable NAMES_AGG_C resolves to 
MPRINT(OT_APPEND2): set ; 
MPRINT(OT_APPEND2): run; 
MLOGIC(OT_APPEND2): Ending execution. 
NOTE: There were 1 observations read from the data set C.NEW_NAME_OT. 
NOTE: The data set WORK.TEST has 1 observations and 12 variables. 

NOTE: CALL EXECUTE generated line. 
1 +  proc sql; 
1 +       select    cats("c.",name,"_agg_a"), 
cats("c.",name,"_agg_b"),    cats("c.",name,"_agg_c")   into 
:names_agg_a separated by " ",    :names_agg_b separated by " ", 
2 + :names_agg_c separated by " "   from c.datasets_pit    where portfolio = 
"MTG" and     scorecard = "A" and     event_table = "event_table_name" 
and     scorecard_type = "Application" and 
3 + obs_period = 1 and     outcome_period = 18 and     x_var = "PI" 
and     y_var = "GB_Odds" and     use = "Development" and 
    condition = ""   ;  quit;; data c.MTG_Dev_OT_1_ODDS;  set 
NOTE: PROCEDURE SQL used (Total process time): 
     real time   0.01 seconds 
     cpu time   0.00 seconds 


4 + ; run; 

NOTE: There were 1 observations read from the data set WORK.TEST. 
NOTE: The data set C.MTG_DEV_OT_1_ODDS has 1 observations and 12 variables. 
NOTE: DATA statement used (Total process time): 
     real time   0.00 seconds 
     cpu time   0.00 seconds 


4 +   data c.MTG_Dev_OT_1_GINI;  set ; run; 

NOTE: There were 1 observations read from the data set C.MTG_DEV_OT_1_ODDS. 
NOTE: The data set C.MTG_DEV_OT_1_GINI has 1 observations and 12 variables. 
NOTE: DATA statement used (Total process time): 
     real time   0.00 seconds 
     cpu time   0.00 seconds 


4 +             data c.MTG_Dev_OT_1_DIST;  set ; run; 

NOTE: There were 1 observations read from the data set C.MTG_DEV_OT_1_GINI. 
NOTE: The data set C.MTG_DEV_OT_1_DIST has 1 observations and 12 variables. 
NOTE: DATA statement used (Total process time): 
     real time   0.00 seconds 
     cpu time   0.00 seconds 

Respuesta

7

Puede retrasar las invocaciones de macro con %nrstr(), entonces funciona bien.

/* test data */ 
    data dataset; 
    name="a"; condition="1"; output; 
    name="b"; condition=" "; output; 
    name="c"; condition="1"; output; 
    run; 

    data a_agg; v="a_agg"; run; 
    data b_agg; v="b_agg"; run; 
    data c_agg; v="c_agg"; run; 

    data meta_table; 
    condition="1"; name_ot="ot1"; output; 
    condition="2"; name_ot="ot2"; output; 
    condition=" "; name_ot="ot_"; output; 
    run; 

    %macro one(condition); 
    %global names_agg; 
    %let names_agg = ; 
    proc sql noprint; 
     select cats(name,"_agg") into :names_agg separated by " " 
     from dataset where condition = "&condition."; 
    quit; 
    %mend; 

    %*-- just checking --*; 
    %one(condition=1) %put names_agg=&names_agg; 
    %one(condition=2) %put names_agg=&names_agg; 
    %one(condition=) %put names_agg=&names_agg; 
    %*-- on log 
    names_agg=a_agg c_agg 
    names_agg= 
    names_agg=b_agg 
    --*; 

    %macro two(name_ot); 
    %if &names_agg= %then %do; 
     data &name_ot.; run; 
    %end; %else %do; 
     data &name_ot.; 
     set &names_agg.; 
     run; 
    %end; 
    %mend; 

    data _null_; 
     length code $200; 
     set meta_table; 
     code = catt('%one(', condition, ")"); 
     code = catt(code, '%two(', name_ot, ")"); 
     code = catt('%nrstr(', code, ")"); 
     call execute(code); 
    run; 

    /* check */ 
    title ot1; proc print data=ot1; run; title; 
    /* on lst 
    ot1 
    Obs  v 
    1  a_agg 
    2  c_agg 
    */ 
    title ot2; proc print data=ot2; run; title; 
    /* on log 
    NOTE: No variables in data set WORK.OT2. 
    */ 
    title ot_; proc print data=ot_; run; title; 
    /* on lst 
    ot_ 
    Obs  v 
    1  b_agg 
    */ 
+0

Gracias Chang! Acabo de agregar% nrstr a mi código y ¡ha resuelto mi problema! – MarkG

0

A menos que haya Pared posterior mucho de las macros para el ejemplo que has enviado, es difícil ver por qué podría hacer esto con dos macros, en lugar de sólo uno (o de hecho por qué te gustaría utilizar macros para hacer esto en absoluto) como esto:

%macro TheOnlyOne(condition,name_OT); 
    proc sql noprint; 
    select cats(name,"_agg") 
    into :names_agg separated by " " 
    from dataset 
    where condition="&condition"; 
    quit; 
    data &name_OT; 
    set &names_agg; 
    run; 
%mend; 

de todos modos, WRT su pregunta acerca de lo que está pasando con las variables macro entre las llamadas etc., has

  • Ejecución de las macros secuencialmente fuera de la llamada e ¿método xecute?
  • Configuración options mprint mlogic symbolgen; antes de la ejecución para ver la información de depuración en el registro?
  • Usando algunas declaraciones %put en sus macros, y put declaraciones en su dataspa call execute, para ver qué se está generando en varios puntos?

Se recomienda el desarrollo de aplicaciones macro para obtener por primera vez el código que se ejecuta sin necesidad de utilizar macros en absoluto, a continuación, añadir las variables macro y explícitamente %let -ting sus valores, a continuación, para ello, en el contexto de una macro. Pasar a call execute sería después de eso.

Quizás intentes algunos de los puntos anteriores y vuelvas con algún resultado de log que podamos depurar. Hay un par de otros errores/problemas en el código que ha publicado, pero en lugar de señalarlos supongo que está reduciéndolo para la publicación SO.

BTW Me gusta la idea de conducir código basado en datos usando data _null_ con call execute, uso mucho este enfoque.

+0

Hola sasfrog, llegué a usar inicialmente una sola macro que funciona cuando se acaba de ejecutar la macro normalmente, pero dentro de la llamada ejecutar la variable & name_agg está vacía la primera vez que se ejecuta, pero tiene el valor de la última ejecución si corre de nuevo. – MarkG

+0

Por esta razón, lo dividí en 2 macros pensando que se resolverá y names_agg cuando la macro ONE termine para que pueda usarse en la macro DOS. De nuevo, esto funciona bien normalmente, pero el mismo problema existe en la ejecución de la llamada. Parece que la variable & name_agg solo se resolverá al final de la ejecución de la llamada, es decir, puede haber ejecutado las macros x veces dependiendo de lo que especifique en la tabla de metadatos, pero solo generará el último & name_agg después de que se hayan completado todas las macros. – MarkG

+0

@MarkG, todo lo que puedo sugerir es que utilices las técnicas de depuración de macros enumeradas en mi publicación, y quizás ejecutes el paso 'data _null_' con' obs = 1' para que solo se ejecute una vez. Entonces tendremos un registro para examinar. Y definitivamente haga lo que @Rob sugiere con comillas simples. – sasfrog

1

es probable que tenga que cambiar las comillas dobles a comillas simples en su datastep así:

data _null_; 
    length code $32767; 
    set meta_table; 
    code = '%ONE(' || cats(condition) || '); %TWO(' || cats(Name_OT) || ");"; 
    call execute(code); 
run; 

En este momento el procesador de macros está tratando de resolver los símbolos de porcentaje en la tercera línea. Puede evitar que lo haga ocultándolo con comillas simples.

+0

Hola Rob, traté de usar comillas simples como sugeriste, pero el problema todavía existe. Básicamente & names_agg no se crea antes de que se ejecute la macro DOS. ¡Gracias por tu respuesta! – MarkG

+0

+1 para ti @Rob - ¿Cómo lo extrañé? :) – sasfrog

Cuestiones relacionadas