I have some code that I need to put in a DO LOOP. My code works perfectly outside the loop, but I can't seem to make it work inside it.
What it does is that it takes a global macro variable that has some numbers in them and extracts one number at a time, using that to do calculations:
%LET N=5;
/* example of macro var Price = 1000 1200 1300 5000 4500 */
%MACRO RED();
%DO j=1 %TO &N.;
DATA Client;
SET Client;
Red=%SCAN(&Price.,&j.+1," ");
IF Red-Cost>0 THEN OUTPUT;
RUN;
%END;
%MEND;
%RED()
I tried a different version of the Scan function, but it doesn't work:
Red=%SCAN(&Price.,%eval(&j.+1)," ");
Technically, " " is incorrect within a %SCAN function ... unless you want both quotes and blanks to be delimiters. But that wouldn't cause a problem in this particular case. The better delimiter would be %str( )
One problem is using &j.+1 instead of &j. When &J=5, the %SCAN function returns no characters (because &PRICE only contains 5 words) and your DATA step statement becomes:
Red= ;
Is that the only problem you are encountering?
Your in a data step, you can use SCAN, you don't need the macro version.
Also, what does &Price resolve to, and does that make sense within the comcept of a data step. Ie Is if a list or a variable?
@Elle wrote:
Actually, if I put SCAN instead of %SCAN I get another type of error: "Expecting an arithmetic operator".
&Price is a global variable that stores all the possible prices for an item. I use it to compare it to a column in my dataset. If the difference is positive I need to flag it and output everything up until that point into a different dataset (RedData), then remove all these rows from the Client dataset and begin all over again until there are no more rows for that client
%scan is a macro function; since macro language only knows the datatype text, quotes are not necessary (they even are wrongly used and cause problems in many cases). So you can use &price. as such
scan, OTOH, is a data step function, and needs a variable of type char or a string literal as its first parameter, so you have to use &price as a literal with quotes:
scan("&price.",&j.,' ')
In your case, I'd prefer to use %scan. Why? Because the substring extraction is performed once by the macro engine before the data step is compiled, while the data step function would be executed in each data step iteration when the step is executed. Therefore %scan is better performancewise.
PS and since red is meant to be a numeric variable, you would need
red = input(scan("&price.",&j.,' '),best.);
to make it so.
Technically, " " is incorrect within a %SCAN function ... unless you want both quotes and blanks to be delimiters. But that wouldn't cause a problem in this particular case. The better delimiter would be %str( )
One problem is using &j.+1 instead of &j. When &J=5, the %SCAN function returns no characters (because &PRICE only contains 5 words) and your DATA step statement becomes:
Red= ;
Is that the only problem you are encountering?
When &j = 5, your %scan tries to look for word 5+1, which is not there and therefore the %scan function call returns an emtpy string, causing a syntax error. (see log!!)
You also use the same dataset name in the data and set statements, causing permanent overwrites during the macro loop iteration.
Try this instead:
data client;
input id $ cost;
cards;
a 900
b 1100
c 1400
d 4600
e 5100
;
run;
%let price=1000 1200 1300 5000 4500;
%macro red;
%do j = 1 %to %sysfunc(countw(&price.,' '));
data client&j.;
set client;
red=%scan(&price.,&j.," ");
if red - cost > 0 then output;
run;
%end;
%mend;
%red
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.