2010-11-11 15 views
5

Ho due macro sotto che sto cercando di eseguire 1 dopo l'altro come un loop utilizzando una tabella di metadati e il comando di esecuzione della chiamata in un passo di dati.Problema di variabili macro quando si utilizza la chiamata execute

macro% TWO richiede la variabile globale & names_agg. che dovrebbe essere creato nella macro% ONE. Tuttavia, nel codice seguente, & names_agg è vuoto la prima volta che lo eseguo. Se lo eseguo di nuovo, manterrà solo il valore dall'ultima volta che viene eseguito.

L'idea è che ogni volta che viene eseguito% ONE, un nuovo & names_agg. è creato.

Cosa sto sbagliando?

Grazie

%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; 

Mi dispiace per il registro disordinato, questo è il codice vero e proprio. Il problema è con NAMES_AGG_A _B e _C non risolvendo correttamente

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 

In sostanza il problema è qui, put dichiarazione di cui sopra nella chiamata eseguire spettacoli che NAMES_AGG_A risolve nulla.

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 

risposta

7

È possibile ritardare le chiamate di macro con %nrstr(), quindi funziona correttamente.

/* 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

Grazie Chang! Ho appena aggiunto% nrstr al mio codice e ha risolto il mio problema! – MarkG

0

meno che non hai sbucciato indietro molto dai macro per l'esempio che hai postato, è difficile capire perché si dovrebbe fare questo con due macro, piuttosto che uno solo (o anche il motivo per cui ci si utilizzare le macro per fare questo a tutti) in questo modo:

%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; 

in ogni caso, WRT le tue domande su cosa sta succedendo con le variabili macro tra le chiamate, ecc, hai provato

  • esecuzione delle macro in sequenza fuori della chiamata e metodo xecute?
  • Impostazione options mprint mlogic symbolgen; prima dell'esecuzione per visualizzare le informazioni di debug nel registro?
  • Utilizzando alcune istruzioni %put nelle macro e le dichiarazioni put nel proprio disco di dati call execute, per vedere cosa viene generato in vari punti?

E 'consigliato quando lo sviluppo di applicazioni di macro alla prima ottenere il codice in esecuzione senza l'utilizzo di macro a tutti, quindi l'aggiunta di variabili macro e in modo esplicito %let -ting i loro valori, poi prova nel contesto di una macro. Passare a call execute sarebbe dopo.

Forse provare alcuni dei suddetti punti e tornare con un output di registro che possiamo eseguire il debug. Ci sono un paio di altri errori/problemi nel codice che hai postato, ma piuttosto che indicarli, presumo che tu lo stia riprendendo per il post SO.

BTW Mi piace l'idea di guidare il codice basato sui dati utilizzando data _null_ con call execute, io uso questo approccio molto.

+0

Ciao sasfrog, ho fatto inizialmente utilizzare un unico macro che funziona quando appena l'esecuzione della macro normalmente, ma dentro la chiamata eseguire il & variabile name_agg è vuoto la prima volta che viene eseguito, ma ha il valore dell'ultimo periodo se esegui di nuovo. – MarkG

+0

Per questo motivo l'ho diviso in 2 macro pensando che si risolverà & names_agg quando la macro ONE termina, quindi può essere usata nella macro DUE. Anche in questo caso funziona normalmente, ma lo stesso problema esiste nell'esecuzione della chiamata. Sembra che la variabile & name_agg si risolva solo alla fine della chiamata execute, vale a dire che potrebbe aver eseguito i macro x volte a seconda di quanto specificato nella tabella dei metadati, ma genererà solo l'ultimo & name_agg dopo che tutte le macro sono state completate. – MarkG

+0

@MarkG, tutto quello che posso suggerire è che tu usi le tecniche di debug della macro elencate nel mio post, e forse esegui il passo 'data _null_' con' obs = 1', quindi viene eseguito una sola volta. Quindi avremo qualche registro da esaminare. E sicuramente fai ciò che @Rob suggerisce con virgolette singole. – sasfrog

1

è probabilmente necessario modificare i doppi apici per apici nella vostra datastep in questo modo:

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

In questo momento il processore macro sta cercando di risolvere i simboli di percentuale nel 3 ° riga. Puoi impedirgli di farlo nascondendoli usando le virgolette singole.

+0

Ciao Rob, ho provato ad utilizzare le virgolette singole come suggerito, ma il problema esiste ancora. Fondamentalmente & names_agg non viene creato prima dell'esecuzione della macro TWO. Grazie per la tua risposta! – MarkG

+0

+1 per te @Rob - come mi sono perso? :) – sasfrog

Problemi correlati