DATA Step, Macro, Functions and more

call Symput inside macro problem

Reply
New Contributor
Posts: 2

call Symput inside macro problem

I am currently having a problem with this SAS program:

/**** PROGRAM SUMMARY AND INPUTS ****/

%LET simloadfl=1;    /* Set 'simloadfl' to 1 to simulate load (and then update load sim inputs).  */
%LET p_inputs='I:\2013_MTP\Budget\Simulations\Inputs\';  /* Folder input files are located.        */
%LET fn_NGPrices='tblMonthlyGasPrices2013BP_HI.csv';  

/* Create library for permanent SAS datasets. */
libname prosym &p_inputs;

options mprint mlogic symbolgen;

%MACRO loadsims;
/* The following variables will be used in the process to import user-specified input files. */
data _NULL_;
  call symput("pfn_NGPrices",cats("'",&p_inputs,&fn_NGPrices,"'"));
  %PUT &pfn_NGPrices;
run;
/* Monthly gas prices */
proc import datafile = &pfn_NGPrices out = inp_NGPrices DBMS = CSV REPLACE;
run;
%MEND loadsims;

data _NULL_;
if &simloadfl = 1 then call execute('%loadsims');
run;

What is supposed to happen is that the path and filename are loaded separately into two variables using %LET statements. The reason for this is that many inputs will be used but they will all be in the same folder so it is easier to just list the path once instead of including it with each filename. The macro loadsims is supposed to concatenate the filename and path together and put them in the variable pfn_NGPrices using call symput in a data step. The proc import statement should then import the file located at the address pfn_NGPrices.

The problem is that each time the program is run, the pfn_NGPrices that is actually read is from the last time I ran this program. As an example, if I  run the program once using the let statement:

%LET fn_NGPrices='tblMonthlyGasPrices2013BP_HI.csv';  

And this is the first time I have run the program since opening SAS Enterprise, it will import the correct file. If I then change the let statement to read:

%LET fn_NGPrices='tblMonthlyGasPrices2013BP_LO.csv';  

And run the program again, it will import the tblMonthlyGasPrices2013BP_HI.csv (the name from the previous run) instead of correctly importing tblMonthlyGasPrices2013BP_LO.csv.

My best guess is that so SAS enters the loadsims macro, sees the &pfn_NGPrices and fills it with whatever value it has handy (this would be why the value of the previous run is filled in), THEN it goes back, does the call symput step and fills in the correct value to the pfn_NGPrices variable  which is why it works correctly on the next run. See: http://www2.sas.com/proceedings/sugi31/251-31.pdf

But I’m not sure if my understanding of the flow of SAS programs is correct. Does anyone know if this might be the problem and if so how to fix it? I’m still somewhat confused about how SAS interprets and executes macros. Thanks for the help!

New Contributor
Posts: 2

Re: call Symput inside macro problem

Ok, SAS tech support got back to me very quickly with the following solution:

"

It is a timing issue between CALL EXECUTE and CALL SYMPUT.  The following change to your code should give you what you are looking for:

  if &simloadfl = 1 then call execute('%nrstr(%loadsims)');

"

This worked but I'm still a little bit confused as to why it worked. I looked up the %nrstr function and read about it in the SAS reference but I'm still kind of confused as to exactly how this works.

Super User
Posts: 17,797

Re: call Symput inside macro problem

not 100% but my guess.

When the macro is compiled, the macro variable resolves, so every time you call that macro it doesn't actually look for that macro variable, its already resolved.

A better way would be to add in parameters to your macro:

/**** PROGRAM SUMMARY AND INPUTS ****/

%LET simloadfl=1;    /* Set 'simloadfl' to 1 to simulate load (and then update load sim inputs).  */
%LET p_inputs='I:\2013_MTP\Budget\Simulations\Inputs\';  /* Folder input files are located.        */
%LET fn_NGPrices='tblMonthlyGasPrices2013BP_HI.csv';  

/* Create library for permanent SAS datasets. */
libname prosym &p_inputs;

options mprint mlogic symbolgen;

%MACRO loadsims (file_import, inputs);
/* The following variables will be used in the process to import user-specified input files. */
data _NULL_;
  call symput("pfn_NGPrices",cats("'&file_importt,&inputs, "'"));
  %PUT &pfn_NGPrices;
run;
/* Monthly gas prices */
proc import datafile = &pfn_NGPrices out = inp_NGPrices DBMS = CSV REPLACE;
run;
%MEND loadsims;

data _NULL_;
if &simloadfl = 1 then call execute('%loadsims(PARAMETER VALUES HERE, AND HERE )');
run;

Super User
Posts: 5,081

Re: call Symput inside macro problem

What did you examine to determine that the wrong file was used?  The %PUT statement, or the log for PROC IMPORT?

At any rate, there is a slightly different timing issue that you should address.  The %PUT statement runs before the DATA _NULL_ statement begins to execute.  So the %PUT statement is always a step behind.  Switch the order of %PUT and RUN statements at the end of the DATA _NULL_ step and see what happens.

Good luck.

Regular Contributor
Posts: 241

Re: call Symput inside macro problem

Are these data _null_ steps necessary? Unless I am missing something, consider a simpler approach like:

  %macro load(folder, file, load=1);
    %local path;
    %let path=%sysfunc(quote(&folder.&file));
    %put NOTE: path=&path;
    %if &load=1 %then %do;
      proc import datafile=&path out=data dbms=csv replace;
      run;
    %end; %else;
      %put NOTE: not imported. load=&load.;
    %end;
  %mend  load;
 
  %*-- usage example --*;
  %load(c:\my folder\, my file.csv)

Ask a Question
Discussion stats
  • 4 replies
  • 424 views
  • 1 like
  • 4 in conversation