I’m running a macro with a call execute in a data step. What I want from my data step is the following:
Take a table, add a new column for every existing column (via macro) and finally add a new column that is the sum of two others. I guess it is also possible without a macro, but I want it exactly this way cause I’m new to SAS and want to understand the logic of macros and call execute.
So let’s say I have the following table:
data values;
input a1 a2 b1 b2;
datalines;
1 0 3 10
0 5 6 11
7 8 9 0
;
run;
and this macro:
%macro loop1(myDataset);
proc contents data=&myDataset. out=Col_Names (keep=Name) noprint;
run;
proc sql noprint;
select count(Name) into :length from Col_Names;
quit;
%do j = 1 %to &length;
data &myDataset.;
set &myDataset.;
n&j=0;
run;
%end;
%mend;
then the following data step creates different output the first three times I run it: (After every run I re-run the original data step with the datalines of course)
data values;
set values;
if _n_=1 then call execute('%loop1(values);');
test=sum(a1,a2);
run;
The first run results in an error:
WARNING: Apparent symbolic reference LENGTH not resolved. ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: &length ERROR: The %TO value of the %DO J loop is invalid. ERROR: The macro LOOP1 will stop executing.
The second run results in exactly what I want:
The columns a1, a2, b2, b2, test, n1, n2, n3, n4
And from the third run on, the output stays:
The columns a1, a2, b2, b2, test, n1, n2, n3, n4, n5
With the undesired n5 in it.
What should I change to always get the output from the second run?
When calling macros using
call execute
it is recommended to wrap them in%nrstr()
as per the following usage note:http://support.sas.com/kb/23/134.html
This prevents premature macro execution - or at least, forces it to wait for any dependent macro variables to be ready, namely the
length
variable in yourINTO:
clause.In order to get the results you desire, you also need to exclude the 'test' variable in your SQL procedure, as follows: