mac_21
mac_21

Reputation: 113

Call execute not working in SAS

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

Answers (2)

Tom
Tom

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

user667489
user667489

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

Related Questions