I have a large number of loops to run and want to save the data every 1000 loops or so.
In the code below, rather than saying %if &v.=5 or &v.=10 or &v=15 or &v.=20, I'd like to say if &v is a multiple of 5. Any suggestions would be greatly appreciated
data a1; input id $ count ;
datalines;
A 1
A 2
A 3
A 4
A 5
A 6
A 7
A 8
A 9
A 10
A 11
A 12
A 13
A 14
A 15
A 16
A 17
A 18
A 19
A 20
;
proc datasets; delete bb;
libname saveme 'f:\temp\saveme';
%macro loop;
%do v=1 %to 20;
data b; set a1; if count=&v.;
count_sq=count**2;
proc append base=bb data=b;
%if &v.=5 or &v.=10 or &v.=15 or &v.=20 %then %do;
%let x=%eval(&v./5);
data saveme.eth_&x.; set bb;
proc datasets; delete bb;
%end;
%end;
%mend loop;
%loop;
run;
Since you ask for selecting every fifth loop: 5, 10, 15, 20, ... The last digit is always 0 or 5, it is a very simple mathematical phenomenon.
So you can validate if the last number of &v. in (0 5) or not.
%macro loop/minoperator;
%do v=1 %to 20;
data b; set a1; if count=&v.;
count_sq=count**2;
proc append base=bb data=b;
%if %substr(&v.,%length(&v.)) in (0 5) %then %do;
%let x=%eval(&v./5);
data saveme.eth_&x.; set bb;
proc datasets; delete bb;
%end;
%end;
%mend loop;
Note: To use in operator in macro, you need to add "minoperator
" behind you macro definition statement.
Take advantage of the fact that macro language performs integer arithmatic, dropping any remainders. Try:
%if &v = &v / 5 * 5 %then %do;
Since you ask for selecting every fifth loop: 5, 10, 15, 20, ... The last digit is always 0 or 5, it is a very simple mathematical phenomenon.
So you can validate if the last number of &v. in (0 5) or not.
%macro loop/minoperator;
%do v=1 %to 20;
data b; set a1; if count=&v.;
count_sq=count**2;
proc append base=bb data=b;
%if %substr(&v.,%length(&v.)) in (0 5) %then %do;
%let x=%eval(&v./5);
data saveme.eth_&x.; set bb;
proc datasets; delete bb;
%end;
%end;
%mend loop;
Note: To use in operator in macro, you need to add "minoperator
" behind you macro definition statement.
An option that is very useful is the MINOPERATOR, which allows use of the IN comparison, especially when the case might not involve wanting a choice that can be easily derived with numeric manipulation. The option on the macro of MINOPERATOR means the operator is available. If you want to use something other than the default blank for the separator between values you use the MINDELIMITER option.
%macro loop / minoperator; %do v=1 %to 20; data b; set a1; if count=&v.; count_sq=count**2; proc append base=bb data=b; %if &v. in (5 10 15 20) %then %do; %let x=%eval(&v./5); data saveme.eth_&x.; set bb; proc datasets; delete bb; %end; %end; %mend loop;
STRONG suggestion for future questions: Do not include custom library assignments or use those libraries in the body of the code. We very likely do not have your drives/paths or even same operating systems. Just include the pieces that you really need to demonstrate the issue.
Second suggestion: In macro code always explicitly provide run; and/or quit; (datasets) to terminate the procedures inside the body of a macro. You never know exactly what the code following a given macro might be and leaving procedures like Datasets still running may cause some very interesting debugging situations. Your current macro leaves datasets running.
Use modulus function, which returns the remainder.
E.g.
when we divide 5 by 5 we get remainder 0. So Mod(5,5)=0 is True.
when we divide 10 by 5 we get remainder 0. So Mod(10,5)=0 is True.
but when we divide 11 by 5 we get remainder 1. So Mod(11,5)=0 is False.
Mod(&v.,5)=0
Hope this will resolve your issues.
-Vijay
Thanks all - very helpful. Was not aware of the minoperator.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.