Here's my code, I simplified my problem as this:
%macro checkrow(dsname);
%let dsid=%sysfunc(open(&dsname));
%let countrow=%sysfunc(attrn(&dsid,nlobs));
%let rc=%sysfunc(close(&dsid));
&countrow
%mend checkrow;
data t1;
input a b $;
datalines;
1 a
2 b
;
run;
%put %checkrow(t1);
%macro t2;
data t1;
set t1 t1;
run;
%put %checkrow(t1);
%mend t2;
data _null_;
do i = 0 to 3;
call execute('%t2');
end;
run;
the macro checkrow is used to check how many rows in a dataset and it works well. But here's the problem
Every iteration in the data_null_, the row of dataset t1 is doubled, so my expectation is
2
2
4
8
16
But the output is
2
2
2
2
2
although the actual t2 rows are already 16
Could anyone tell me why? Why the %checkrow(t2) don't work here?
Try it this way:
data _null_;
do i = 0 to 3;
call execute('%nrstr(%t2)');
end;
run;
***************** EDITED to explain:
CALL EXECUTE asks SAS to execute the statements as soon as possible. That doesn't mean that they execute when you would expect.
When CALL EXECUTE generates DATA and PROC statements, those can't run immediately. After all, CALL EXECUTE appears in the middle of a DATA step. So additional DATA and PROC statements have to wait until the current DATA step finishes.
However, macro programming statements are able to run immediately, before the current DATA step finishes executing. So a %LET or %PUT statement, for example, within the definition of %T2 runs right away.
%NRSTR temporarily masks the % (in %t2) so that the macro processor doesn't immediately recognize it as being a macro command. The net effect is that %t2 waits to execute, until the current DATA step is complete.
Per the documentation on call execute(argument)
If argument resolves to a SAS statement or if execution of the macro generates SAS statements, the statement(s) execute after the end of the DATA step that contains the CALL EXECUTE routine.
Use this code instead.
%macro checkrow(dsname);
%let dsid=%sysfunc(open(&dsname));
%let countrow=%sysfunc(attrn(&dsid,nlobs));
%let rc=%sysfunc(close(&dsid));
&countrow
%mend checkrow;
data t1;
input a b $;
datalines;
1 a
2 b
;
run;
%put %checkrow(t1);
%macro t2;
%do i = 0 %to 3;
data t1;
set t1 t1;
run;
%put %checkrow(t1);
%end;
%mend t2;
%t2;
Thank you very much for your reply. It works in this condition. Now I know it's the problem of call execute. But in the real case what I'm doing, which is much more complex, I have to make input to the macro %t2, and the input is from other dataset. So is there other way other than call execute that I can use this macro(and also input variables) in a data step?
Try it this way:
data _null_;
do i = 0 to 3;
call execute('%nrstr(%t2)');
end;
run;
***************** EDITED to explain:
CALL EXECUTE asks SAS to execute the statements as soon as possible. That doesn't mean that they execute when you would expect.
When CALL EXECUTE generates DATA and PROC statements, those can't run immediately. After all, CALL EXECUTE appears in the middle of a DATA step. So additional DATA and PROC statements have to wait until the current DATA step finishes.
However, macro programming statements are able to run immediately, before the current DATA step finishes executing. So a %LET or %PUT statement, for example, within the definition of %T2 runs right away.
%NRSTR temporarily masks the % (in %t2) so that the macro processor doesn't immediately recognize it as being a macro command. The net effect is that %t2 waits to execute, until the current DATA step is complete.
Wow, it works. Could you briefly explain it a little bit?
@zhaoxuan210 wrote:
Wow, it works. Could you briefly explain it a little bit?
There are two timing issues with CALL EXECUTE(). The main one, as explained in the manual per the post above in this thread, is that the code is stacked up to run after the current data step finishes.
The second timing issue is that macro triggers in the string that you pass to CALL EXECUTE() are processed by the macro processor immediately and the resulting code is what makes its way onto the stack to run after the data step runs. By adding the %NRSTR() into the string that is passed this resolution by the macro processor is delayed until when the code is pulled back off of the stack to execute.
For this problem that second timing issue is critical because at the time the CALL EXECUTE() statement runs the dataset that the macro wants to open and examine is still being created!
Thank you for your explain! Yes the second timing problem is shown in this case. I'll also be care about the first timing problem. I really think maybe SAS can consider to make some change so that the program runs in the order it looks like.
Thank you for your explain!
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.