BookmarkSubscribeRSS Feed
yym
Calcite | Level 5 yym
Calcite | Level 5

Hi, I was trying to create lag variables for all my variables in the data. To make it easy, assusme I only have two variables in the data: a and b. However the code below does not work. 

 

data t2;
set t;
do i=1 to 2;
%let var=%scan(&vars.,i);
&var._lag1 = lag1(&var.);
end;
run;

 

The errow message was "ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: i
ERROR: Argument 2 to macro function %SCAN is not a number."

 

but after I put it in macro function the code below works. Can anybody help me to understand the reason?


%macro ts;
data t2;
set t;
%do i=1 %to 2;
%let var=%scan(&vars.,&i.);
&var._lag1 = lag1(&var.);
%end;
run;
%mend;
%ts;

 

11 REPLIES 11
Astounding
PROC Star

What do you mean by "the code below works"?  The error message might disappear, but does it really do what you want it to do?

yym
Calcite | Level 5 yym
Calcite | Level 5

yes it does what I wanted. But I am trying to figure out why the first part does not work

ballardw
Super User

Run the code with OPTIONS MPRINT; run prior to the call to the macro. The log will show the code generated by the macro call. That may help you see why it isn't doing quite what you expect.

Astounding
PROC Star

OK ... it doesn't work because macro language does not use data step variables.  This expression causes trouble:

 

%let var=%scan(&vars.,i);

 

The last parameter to %scan, "i", is just text.  It is not a reference to a variable.

Reeza
Super User
Your mixing a data step loop with a macro loop. The data step loop does not create a macro variable, i, but the macro loop does.
FreelanceReinh
Jade | Level 19

The %LET statement cannot be used in a data step, although it does not always cause a syntax error if it is (misleadingly) placed inside a data step.

 

As a macro language statement it is executed before the data step is even compiled. Therefore, values of data step variables are unavailable to it. For the data step, in turn, the %LET statement is completely invisible.

 

The same holds for other macro language statements which are valid in open code. For example, try a %PUT statement in an IF-THEN-DO-END block of a data step. You will see that %PUT is executed regardless of the IF condition being true or false and even if compilation of the data step stops prematurely because of some syntax error. So, it does not make sense to place it there.

 

Ksharp
Super User

Make a macro variable to hold these statement. OR Would you like to use IML code ?

 

data have;
 set sashelp.class;
run;
proc sql;
 select cats(name,'_lag1=lag(',name,')') into : lag separated by ';'
  from dictionary.columns 
   where libname='WORK' and memname='HAVE' and type='num';
quit;
data want; 
 set have;
 &lag ;
run;
srinath_gatpa
Returning User | Level 2

Hi,

 

%scan function distinctively designed for Macro's, but here, you are mixing macro function in open source data step. SAS does not allow you to do this. when ever you call / create any macro related functionality it sould be done within the macros(though there are exeptions like creating macro varible using Call symput).

 

Thank you,

Srinath.

aditya10
Calcite | Level 5

As macro statements are executed prior to DATA step statements, macro function %scan considers i as the character 'i' and hence the error. The variable 'i' only gets created at data step execution phase. 

Call execute comes to rescue. SAS statements produced by the EXECUTE routine do not execute until after the step boundary has been passed & that's when variable 'i' is created and can be used.

 

Below code should work (although I am not sure what is the objective of the code. Also, 3rd argument may be required to %scan; lag<n> is unavailable as a macro function)

 

data t2;
set t;
do i=1 to 2;

call execute ( '%let  var = %scan(&vars,' || i || ',%str( ) )' );

call execute ( '%let  &var._lag1 = lag1(&var.)' );
end;
run;

Reeza
Super User

@aditya10 Please don't post on really really old threads, if you have a related question please post a new question and feel free to link if necessary. The reason for this is no one will see it if it's that old, only users who originally interacted in this thread.

 


@aditya10 wrote:

As macro statements are executed prior to DATA step statements, macro function %scan considers i as the character 'i' and hence the error. The variable 'i' only gets created at data step execution phase. 

Call execute comes to rescue. SAS statements produced by the EXECUTE routine do not execute until after the step boundary has been passed & that's when variable 'i' is created and can be used.

 

Below code should work (although I am not sure what is the objective of the code. Also, 3rd argument may be required to %scan; lag<n> is unavailable as a macro function)

 

data t2;
set t;
do i=1 to 2;

call execute ( '%let  var = %scan(&vars,' || i || ',%str( ) )' );

call execute ( '%let  &var._lag1 = lag1(&var.)' );
end;
run;


 

Tom
Super User Tom
Super User

Thanks for resurrecting this old thread because none of the answers address the real problem here.

 

The problem is one of not understanding the relationship between macro code and SAS code.  Remember that the macro processor is used to generate text that the SAS processor can interpret as SAS code.   The macro processor cannot understand dataset variables much less access their values.  It cannot use SAS functions (unless you convert them to macro functions by using %SYSFUNC()).

 

In the original question the user tried to use the value of the data step variable I in a call to the macro function %SCAN(). But since the macro processor operates first and just generates text it did not see the letter I as a variable at all, but just as the letter I.  That is why the %SCAN() function generated an error.  Once they enclosed the code into a macro definition and used the %DO statement to create a macro variable (which they also named I) it could use the value of that macro variable as the argument in the %SCAN() function call.  That way the macro do loop was able to generate a series of valid SAS assignment statements that SAS could then use to compile and run the data step.

 

Your proposed solution does not generate any errors, but really does not do anything useful.  What it will do is create the dataset T2 as a copy of the existing dataset T.  It will add an extra variable named I that will be 3 for every observation.  It will also create a macro variable named VAR and a series of macro variables with names that follow the pattern xxx_LAG1 that have the text of a call to the LAG() function.   It will recreate these macro variables over and over again as it processes each observation from the dataset T, but it never uses them (other than the one named VAR) for anything.

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 11 replies
  • 3433 views
  • 0 likes
  • 9 in conversation