BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Elle
Quartz | Level 8

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)," "); 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Astounding
PROC Star

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?

View solution in original post

7 REPLIES 7
Reeza
Super User

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
Quartz | Level 8
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
Kurt_Bremser
Super User

@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.

Astounding
PROC Star

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?

Elle
Quartz | Level 8
Thank you for your suggestion. I'm a bit afraid to use macro functions inside macro functions because I don't master them enough and instead of concentrating on the data I'm losing time trying to debug my program. When I saw this version of SCAN I thought if it works it's good enough, but thank you for your advice. I'll use it next time.And thank you for making me understand where the error came from. I thought it was weird my dataset was actually being created with that error in the log, but now I get it. I've got no more problems with the code, as crazy as that sounds. Thank you 🙂
Kurt_Bremser
Super User

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
Elle
Quartz | Level 8
Thank you for the suggestion. I've solved the problem now. Also, the overwriting of the table was supposed to happen because I eliminate rows if they meet a certain condition and re-start the analysis on the remaining ones until there are no more left. Thank you very much.

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 7 replies
  • 5051 views
  • 5 likes
  • 4 in conversation