Reputation: 113
data numbers;
input num;
datalines;
3
1
3
;
run;
%macro temp(num);
proc sql noprint;
select count(*) into :count from numbers;
quit;
%if (&num eq &count) %then
%put Match Found;
%else
%put No Match Found;
%symdel count;
%mend;
data _NULL_;
set numbers;
call execute('%temp('||num||')');
run;
Why this code is showing error though everything is correct. I am checking the values in data set number to find match between overall count with variable number (just for practice) I got count using proc SQL, after checking the conditions I am deleting the count macro variable. After execution why SAS is giving the error message. Please explain whats really happening in this code.
LOG-----when I execute the last data step--------->
6188 data _NULL_;
6189 set numbers;
6190 call execute('%temp('||num||')');
6191 run;
NOTE: Numeric values have been converted to character values at the places given by:
(Line):(Column).
6190:24
Match Found
WARNING: Apparent symbolic reference COUNT not resolved.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric
operand is required. The condition was: &num eq &count
ERROR: The macro TEMP will stop executing.
WARNING: Apparent symbolic reference COUNT not resolved.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric
operand is required. The condition was: &num eq &count
ERROR: The macro TEMP will stop executing.
NOTE: The SAS System stopped processing this step because of errors.
NOTE: There were 3 observations read from the data set WORK.NUMBERS.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
NOTE: CALL EXECUTE generated line.
1 + proc sql;
1 + select count(*) into :count from numbers;
1 + quit;
NOTE: PROCEDURE SQL used (Total process time):
real time 0.09 seconds
cpu time 0.00 seconds
2 + proc sql;
2 + select count(*) into :count from numbers;
2 + quit;
NOTE: PROCEDURE SQL used (Total process time):
real time 0.15 seconds
cpu time 0.01 seconds
3 + proc sql;
3 + select count(*) into :count from numbers;
3 + quit;
NOTE: PROCEDURE SQL used (Total process time):
real time 0.15 seconds
cpu time 0.01 seconds
Upvotes: 1
Views: 690
Reputation: 51621
When the CALL EXECUTE() statement runs the code is pushed onto the stack. Since you did not use any macro quoting the macro is actually running and the generated code is pushed onto the stack. So the %IF statement is running before the SELECT statement has run. You can use %NRSTR() to delay this so that the macro call is pushed onto the stack.
call execute(cats('%nrstr(%temp)(',num,')'));
Or just avoid CALL EXECUTE and use a PUT statement to write the code to a file that you can %INCLUDE.
filename code temp;
data _null_;
set numbers;
file code ;
put '%temp(' num ')' ;
run;
%include code / source2 ;
Upvotes: 3
Reputation: 9569
Quoting from the documentation page for call execute:
Note: Because macro references execute immediately and SAS statements do not execute until after a step boundary, you cannot use CALL EXECUTE to invoke a macro that contains references for macro variables that are created by CALL SYMPUT in that macro.
I think what you're trying to do here is essentially the same sort of thing, only using proc sql
's select into
rather than call symput
within your macro.
One way around this limitation is to use the dosubl
function. You can use this to create a function-style macro which you can then run via a %put
statement generated by call execute
:
data numbers;
input num;
datalines;
3
1
3
;
run;
%symdel COUNT;
%macro temp(num);
%sysfunc(dosubl(proc sql noprint;
select count(*) into :count from numbers;
quit;))
%if &num eq &count %then
%put Match Found;
%else
%put No Match Found;
%mend;
data _NULL_;
set numbers;
count = symget('Count');
put "Before call execute " _n_= count=;
call execute('%put rc=%temp('||num||');');
count = symget('Count');
put "After call execute " _n_= count=;
run;
Or alternatively, you can put the dosubl
call in the data step rather than the macro definition:
%symdel COUNT;
%macro temp(num);
proc sql noprint;
select count(*) into :count from numbers;
quit;
%if &num eq &count %then
%put Match Found;
%else
%put No Match Found;
%mend;
data _NULL_;
set numbers;
count = symget('Count');
put "Before call execute " _n_= count=;
rc = dosubl('%temp('||num||')');
count = symget('Count');
put "After call execute " _n_= count=;
run;
Upvotes: -1