2010-11-11 5 views
5

J'ai 2 macros ci-dessous que j'essaie d'exécuter 1 après l'autre comme une boucle en utilisant une table de métadonnées et la commande call execute dans une étape de données. Macro% TWO nécessite la variable globale & noms_agg. Cela est censé être créé dans la macro% ONE. Cependant, dans le code ci-dessous, & names_agg est vide la première fois que je l'exécute. Si je l'exécute à nouveau, il ne conservera que la valeur de la dernière fois qu'il est exécuté. L'idée est que chaque fois que% ONE est exécuté, un nouveau & noms_agg. est créé.Problème de variables macro lors de l'utilisation d'appel

Qu'est-ce que je fais mal?

Merci

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

Désolé sur le journal en désordre, c'est le code réel. Le problème est avec NAMES_AGG_A _B et _C ne résolvent correctement

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 

Essentiellement, le problème est ici, la déclaration de vente ci-dessus dans l'appel execute montre que rien NAMES_AGG_A résout.

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 

Répondre

7

Vous pouvez différer les invocations de macro avec %nrstr(), puis cela fonctionne correctement.

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

Merci Chang! Je viens d'ajouter% nrstr à mon code et cela a résolu mon problème! – MarkG

0

À moins que vous avez Pared retour beaucoup des macros pour l'exemple que vous avez posté, il est difficile de voir pourquoi vous feriez cela avec deux macros, plutôt qu'un seul (ou bien pourquoi vous utiliser des macros pour faire du tout) comme ceci:

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

quoi qu'il en soit, par rapport'a votre question sur ce qui se passe avec les variables macro entre les appels, etc., avez-vous essayé

  • Exécution des macros de façon séquentielle à l'extérieur de l'appel e méthode xecute?
  • Paramètre options mprint mlogic symbolgen; avant l'exécution pour voir les informations de débogage dans le journal?
  • En utilisant quelques instructions %put dans vos macros, et put des déclarations dans votre call execute datastep, afin de voir ce qui est généré à divers points?

Il est recommandé lors de l'élaboration des applications macro d'abord obtenir le code en cours d'exécution sans utiliser macro du tout, puis en ajoutant des variables macro et explicitement leurs valeurs %let Opération permettant, tester puis dans le contexte d'une macro. Passer à call execute serait après cela.

Essayez peut-être quelques-uns des points ci-dessus et revenez avec une sortie de journal que nous pouvons déboguer. Il y a quelques autres erreurs/problèmes dans le code que vous avez posté, mais au lieu de les signaler, je suppose que vous êtes en train de revenir en arrière pour le post SO.

BTW J'aime l'idée de piloter le code piloté par les données en utilisant data _null_ avec call execute, j'utilise beaucoup cette approche.

+0

Salut sasfrog, je ne l'ai d'abord utiliser une macro unique qui fonctionne quand juste d'exécuter la macro normalement, mais à l'intérieur l'appel execute la variable & name_agg est vide la première fois qu'il fonctionne, mais a la valeur du dernier terme si courir à nouveau. – MarkG

+0

Pour cette raison, je l'ai divisé en 2 macros en pensant qu'il résoudra & names_agg lorsque la macro ONE se termine afin qu'il puisse être utilisé dans la macro TWO. Encore une fois cela fonctionne normalement, mais le même problème existe dans l'appel d'exécution. Il semble que la variable & name_agg ne se résoudra qu'à la fin de l'appel, c'est-à-dire qu'elle aura exécuté les macros x fois en fonction de ce que je spécifie dans la table de métadonnées mais générera uniquement la dernière & name_agg après avoir terminé toutes les macros. – MarkG

+0

@MarkG, tout ce que je peux suggérer est que vous utilisez les techniques de débogage de macros listées dans mon article, et peut-être lancer l'étape 'data _null_' avec' obs = 1' pour qu'il ne s'exécute qu'une seule fois. Ensuite, nous aurons un journal à examiner. Et certainement faire ce que @Rob suggère avec des guillemets simples. – sasfrog

1

Vous devez probablement changer les guillemets doubles guillemets simples dans votre datastep comme ceci:

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

En ce moment, le processeur macro tente de résoudre les symboles de pourcentage dans la 3ème ligne. Vous pouvez l'empêcher de le faire en les cachant à l'aide de guillemets simples.

+0

Salut Rob, j'ai essayé d'utiliser des guillemets simples comme vous l'avez suggéré, mais le problème existe toujours. Fondamentalement & names_agg n'est pas créé avant que la macro TWO s'exécute. Merci pour votre réponse si! – MarkG

+0

+1 pour vous @Rob - Comment ça m'a manqué? :) – sasfrog

Questions connexes