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!
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.
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;
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.
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)
Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.
Register today!Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Select SAS Training centers are offering in-person courses. View upcoming courses for: