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

hello,

can concatenate two macros variables  and realize an arithmetic operation as follows:

 

%macro tt(variable=);

data test;
set sashelp.class;
reg=%sysevalf(catx('/',&variable));
run;
%mend;
%tt(variable=%bquote(age,weight));

Thank you

1 ACCEPTED SOLUTION

Accepted Solutions
Quentin
Super User

I suggest you explain more about what your are trying to do, because this looks like an unusual approach.

 

That said, yes, you could define an arithmetic expression like you are trying:

 

%macro tt(variable=);
data test;
set sashelp.class;
reg=%sysfunc(catx(/,%unquote(&variable)));
put (age weight reg)(=) ;
run;
%mend;
%tt(variable=%bquote(age,weight))

Note that I used %SYSFUNC, not %SYSEVALF, because the macro language is not doing math, it's just generating the SAS expression age/weight.

 

Often it's easier to pass the expression as an argument:

 

%macro tt(expression=);
data test;
set sashelp.class;
reg=&expression;
put (age weight reg)(=) ;
run;
%mend;
%tt(expression=age/weight)
BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.

View solution in original post

10 REPLIES 10
RW9
Diamond | Level 26 RW9
Diamond | Level 26

Use 

reg=%sysfunc(catx(/,&variable.));

Not tested as nothing to test on.  Would also question why you want to create such messy code in the first place.

Simply do:

%tt(variable=age / weight);

 

 

Quentin
Super User

I suggest you explain more about what your are trying to do, because this looks like an unusual approach.

 

That said, yes, you could define an arithmetic expression like you are trying:

 

%macro tt(variable=);
data test;
set sashelp.class;
reg=%sysfunc(catx(/,%unquote(&variable)));
put (age weight reg)(=) ;
run;
%mend;
%tt(variable=%bquote(age,weight))

Note that I used %SYSFUNC, not %SYSEVALF, because the macro language is not doing math, it's just generating the SAS expression age/weight.

 

Often it's easier to pass the expression as an argument:

 

%macro tt(expression=);
data test;
set sashelp.class;
reg=&expression;
put (age weight reg)(=) ;
run;
%mend;
%tt(expression=age/weight)
BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
mansour_ib_sas
Pyrite | Level 9

hello RW9, Quentin and thank you for your ansewer,

@Quentin It is the first solution that you proposed to me that I wanted to put in place.

Nevertheless, I have a question.

Using the base language in this step:

%macro tt(variable=);

data test;
set sashelp.class;
reg=catx('/',&variable);
run;
%mend;
%tt(variable=%bquote(age,weight));

the evaluation is not realized.

But whith macro code in step data (your first solution) then evaluation is realized.

Is it related to the phase comiplation ==> generation of the text.

And in the phase execution, the function is evaluated?

Thank you

gamotte
Rhodochrosite | Level 12

Hello,

 

You seem to mix macrovariables an datasets colums. See the following example

 

 

%macro tt(variable=);

data test;
set sashelp.class;
reg=resolve(cats('%sysevalf(',catx('/',&variable),')'));
run;

%mend;

%tt(variable=%bquote(age,weight));

 

with %bquote(age,weight) as the macro parameter :

catx('/',&variable)resolves to catx('/', age, weight) creates a string such as "13/84" (Alice's data in sashelp.class)

cats('%sysevalf(',catx('/',&variable),')') then creates the string '%sysevalf(13/84)'

Then the resolve function is used to evaluate the string as a macro command.

 

In your initial program, you had the instruction

reg=%sysevalf(catx('/',&variable));

catx('/',&variable) creates the same string as above

 

%sysevalf being a macro function is executed first and will raise en error since its argument

is not an arithmetical expression that can be evaluated.

 

@Quentin's solution

%sysfunc(catx(/,%unquote(&variable)));

 takes the catx function and creates its macro equivalent, so it will generate

the code :

reg=age/weight

which will then be executed by the data step.

Quentin
Super User

They key point is to remember that the job of the macro language is to generate SAS code.

 

If you turn on the system option MPRINT it will allow you to see the generated SAS code in the log, which is very helpful.  It's hard to debug without seeing code. : )

 

1    %macro tt(variable=);
2    data test;
3    set sashelp.class;
4    reg=catx('/',&variable);
5    run;
6    %mend;
7    options mprint ;
8    %tt(variable=%bquote(age,weight));
MPRINT(TT):   data test;
MPRINT(TT):   set sashelp.class;
MPRINT(TT):   reg=catx('/',age,weight);
MPRINT(TT):   run;

So your macro generated the SAS statement:

reg=catx('/',age,weight);

That is a valid SAS language statement where the CATX character function will convert AGE and WEIGHT into character values, and concatenated them using '/' as a delimiter, and REG is a character variable holding that concatenated string.

 

But your intention is to generate the SAS statement:

reg=age/weight;

The code in my first answer to generate that statement is:

reg=%sysfunc(catx(/,%unquote(&variable)));

It's a little ugly because it uses the macro language %SYSFUNC function to call the CATX function in order to generate the SAS code, and there is an %unquote() needed because you used %bquote() to mask the comma when you passed the parameters.  This is not the way I recommend doing it, but it shows how the macro language works.

 

Note that the macro language is not doing any mathematical calculations (it's not doing the division), it's simply generating SAS code.   The data step is still compiling the SAS code and then executing it.

 

BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
Tom
Super User Tom
Super User

The macro processor just generates text. If you generate the text in the middle of a SAS statement then SAS will run the generated text.

You wrote this line in your program.

reg=catx('/',&variable);

It has a macro trigger, & , so the macro processor will replace the macro variable reference with its value.

Now you have this line of text (code) for SAS to run.

reg=catx('/',age,weight);

So SAS will define REG as a character variable since you are assigning the value of function that generates character values. 

When the data step runs the CATX() function will execute can convert AGE and WEIGHT into character strings and concatenate them with a slash between them and store the resulting string into the variable REG.

 

What is it that you want to do?  Write the SAS code that does that.  Then figure out how to get the macro processor to generate that SAS code.

Tom
Super User Tom
Super User

If the intent it to generate A/B then why not just pass in TWO arguments to the macro?

%macro tt(numerator,denominator );
data test;
  set sashelp.class;
  reg=&numerator/&denominator;
run;
%mend;
%tt(age,weight);

If the intent is to pass in a list of variables then use SPACES between their names. 

 

%macro t2(varlist );
data test;
  set sashelp.class;
  reg=mean(of &varlist);
run;
%mend;
%t2(varlist=age weight height);
Kurt_Bremser
Super User

Keep in mind that there is the most natural separator in the world, namely the blank:

options mprint mlogic symbolgen;

%macro tt(variable=);

data test;
set sashelp.class;
%let argument=%scan(&variable,1);
%do i = 2 %to %sysfunc(countw(&variable));
%let argument=%sysfunc(catx(/,&argument,%scan(&variable,&i)));
%end;
reg=&argument;
run;

%mend;

%tt(variable=age weight);

No hassle at all with masking/unmasking a comma.

Tom
Super User Tom
Super User

Why would you use %SYSFUNC(CATX())?

%macro tt(variable=);
%local argument i;
%let argument=%scan(&variable,1);
%do i = 2 %to %sysfunc(countw(&variable));
  %let argument=&argument/%scan(&variable,&i);
%end;

data test;
  set sashelp.class;
  reg=&argument;
run;

%mend;

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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
  • 10 replies
  • 1230 views
  • 12 likes
  • 6 in conversation