BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
hellohere
Pyrite | Level 9

I have multiple Macro Variable Assignment Lines, such as below. 

 

%let wtcalc1= abs(a/b-1)*weight; 					
%let wtcalc2=(abs(a/b+c*0.2)*weight;					
%let wtcalc3=(abs(a/b+c*0.4)*weight;

Appearantly direct assignment does not work, such as below, with ot without " ". 

 

%let logicx="%let wtcalc1= abs(a/b-1)*weight; 					
%let wtcalc2=(abs(a/b+c*0.2)*weight;					
%let wtcalc3=(abs(a/b+c*0.4)*weight;";	

How to make it work, to assign into a single macro variable/line?!

 

In case why I am doing this? I need put 'em into one line/macro variable and then attach it 

to the output dataset. That allows me backtrack what logic indeed is used. 

 

Thanks, 

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

You seemed to have skipped explaining a lot of the steps here.

 

If you have macro variables that exist and you want to retrieve their values you can either just reference them.

my_ds_variable = "&my_macro_variable";

Or you could use SYMGET() function.  Which would work better for a lot of macro variables since the name could come from an expression.

length mvar $32 value $200;
do 1=1 to 3;
  mvar=cats('wtcalc',i);
  value = symget(mvar);
  output;
end;

Or just just reference SASHELP.VMACRO.

set sashelp.vmacro;
where name=: 'WTCALC' ;

If you really want to generate that strange macro variable you could do it like this (as long as the macro values do not exceed 200 bytes).

proc sql noprint;
select catx('=',name,value) into :logicx separated by ';%let '
  from dictionary.macros
  where name eqt 'WTCALC'
;
quit;
%let logicx=%nrstr(%let )%superq(logicx)%str(;) ;

If they do then perhaps use a data step instead so you can use SYMGET() to get the full value.

data _null_;
  length logicx $4000 ;
  retain logicx;
  set sashelp.vmacro end=eof;
  where name =: 'WTCALC' and offset=0;
  logicx=cats(logicx,catx(' ','%let',name),'=',symget(name),';');
  if eof then call symputx('logicx',logicx);
run;
%let logicx=%superq(logicx);

But why put this into a macro variable if the goal is to put it into data??

View solution in original post

10 REPLIES 10
hellohere
Pyrite | Level 9

Also I need run with inside the Macro. The code below saves the information. But without "%let" 

and cannot be used inside the macro.  

 

%let wtcalc1= abs(a/b-1)*weight; 					
%let wtcalc2=(abs(a/b+c*0.2)*weight;					
%let wtcalc3=(abs(a/b+c*0.4)*weight;

%let logicx=wtcalc1=&wtcalc1 wtcalc2=&wtcalc2 wtcalc3=&wtcalc3;

%put "&logicx.";
Amir
PROC Star

Hi,

 

Thanks for what you have shared, but it would be helpful to share more information for context. For example, you have not shown us any error message you receive so considering sharing a log (using the Insert Code icon "</>") that shows how the macro assignments are being used and what errors / warnings this brings.

 

The values assigned to macro variables wtcalc2 and 3 have unbalanced brackets, so this might be the root cause of your issues.

 

I ran the following code:

 

%let wtcalc1= abs(a/b-1)*weight;          
%let wtcalc2=(abs(a/b+c*0.2)*weight;          
%let wtcalc3=(abs(a/b+c*0.4)*weight;

%put &=wtcalc1;
%put &=wtcalc2;
%put &=wtcalc3;

 

which gave the following log, with no issues:

 

 72         %let wtcalc1= abs(a/b-1)*weight;
 73         %let wtcalc2=(abs(a/b+c*0.2)*weight;
 74         %let wtcalc3=(abs(a/b+c*0.4)*weight;
 75         
 76         %put &=wtcalc1;
 WTCALC1=abs(a/b-1)*weight
 77         %put &=wtcalc2;
 WTCALC2=(abs(a/b+c*0.2)*weight
 78         %put &=wtcalc3;
 WTCALC3=(abs(a/b+c*0.4)*weight

 

Please try fixing the brackets, and if that doesn't work then share a log showing your code with the error / warning messages and separately explain what result you do want.

 

 

Thanks & kind regards,

Amir.

hellohere
Pyrite | Level 9

Thanks for the attention.

 

Let's forget the () thing. Just take the lines below.

%let wtcalc1= 0.2*weight; 					
%let wtcalc2= 0.5*weight;					
%let wtcalc3= 0.8*weight;

I need same the lines into a single line, which can run inside a macro and store/attach the line 

to dataset for later backtracking. 

 

Thanks, 

 

I am running varied tryouts on calculation logic. Too many variations, easy to get lost how to

get the result datasets. 

 

6749  %let wtcalc1= 0.2*weight;
6750  %let wtcalc2= 0.5*weight;
ERROR: Open code statement recursion detected.
6751  %let wtcalc3= 0.8*weight;
ERROR: Open code statement recursion detected.
6752
6753  %let logicx=%let wtcalc1= 0.2*weight;
ERROR: Open code statement recursion detected.
6754  %let wtcalc2= 0.5*weight;
ERROR: Open code statement recursion detected.
6755  %let wtcalc3= 0.8*weight;
ERROR: Open code statement recursion detected.
6756
6757  %let logicx=\\%let wtcalc1= 0.2*weight;
ERROR: Open code statement recursion detected.
6758  \\%let wtcalc2= 0.5*weight;
ERROR: Open code statement recursion detected.
6759  \\%let wtcalc3= 0.8*weight;
ERROR: Open code statement recursion detected.
6760
6761  %let logicx="%let wtcalc1= 0.2*weight;
ERROR: Open code statement recursion detected.
6762  %let wtcalc2= 0.5*weight;
6763  %let wtcalc3= 0.8*weight;"
6764
6765  %put "logic=&logicx.";
quickbluefish
Barite | Level 11

Agree with @Amir - more context would be helpful.  I'm not sure what you mean by "attach it to the output dataset".  Do you mean as a dataset label?  As a variable that contains this text string as a value?  Also, if you actually have 3 variables in your data called, for example, wt1, wt2, wt3, you could instead store these equations as the labels for those variables, i.e.,

label
    wt1="abs(a/b-1)*weight"
    wt2="(abs(a/b+c*0.2)*weight"
    wt3="(abs(a/b+c*0.4)*weight"
    ;

...but again, it's hard to tell what you're trying to achieve.

Patrick
Opal | Level 21

If attach to the output dataset means storing it in a variable of this dataset then below is a straightforward way of achieving this.

data want;
  set sashelp.class end=last;
  length my_logic $400;
  if last then
    do;
      my_logic=cats('%let wtcalc1=',"&wtcalc1;",'%let wtcalc2=',"&wtcalc2;",'%let wtcalc3=',"&wtcalc3;");
    end;
run;
hellohere
Pyrite | Level 9
Thanks, this works out also.
yabwon
Amethyst | Level 16

First, could you explain more why you need such multiple assignments? It seems to be rather "unusual" strategy for creating macro variables. I personally would seriously reconsider such design.

 

Second, one way to do it would be to go with CALL SYMPUTX() function:

data _null_;
call symputX("logicx", '%let wtcalc1= abs(a/b-1)*weight;%let wtcalc2=(abs(a/b+c*0.2)*weight;%let wtcalc3=(abs(a/b+c*0.4)*weight;', "G");	
run;

Notice the string is in SINGLE quotes!

 

Of course now previewing value of LOGICX may be a bit tricky. If you run just: 

%put &logicx.;

you will get only a bunch of:

ERROR: Open code statement recursion detected.

messages!

 

To preview the value, remember to properly mask LOGICX, for example:

%put %superq(logicx);

(notice there is no & there). Result in the log will be:

1    %put %superq(logicx);
%let wtcalc1= abs(a/b-1)*weight;%let wtcalc2=(abs(a/b+c*0.2)*weight;%let wtcalc3=(abs(a/b+c*0.4)*weight;

 

 

Other option would be to use macro quoting function %NRSTR(), for example like this:

%let logicx= %NRSTR(%%let) wtcalc1=abs(a/b-1)*weight %NRSTR(; %%let) wtcalc2=(abs(a/b+c*0.2)*weight %NRSTR(; %%let) wtcalc3=(abs(a/b+c*0.4)*weight%str(;) ;

Notice that inside %NRSTR() percent symbols have to be escaped with double: %%

To preview value the %SUPERQ() will work, but to call the macro variable and get the masked value "runnable" you will have to unmask it with %UNQUOTE() function:

%unquote(&logicx.)

 

 

As I wrote, I would not go with any of those strategies. But, unless you share your motivation, I cannot propose other strategy too...

 

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



PaigeMiller
Diamond | Level 26

In case why I am doing this? I need put 'em into one line/macro variable and then attach it

to the output dataset. That allows me backtrack what logic indeed is used.

 

Lots of good ideas above. Most of them involving explaining to us in a lot more detail, or re-inventing the process. You would be wise to follow that advice. As with one of your earlier threads @hellohere there's too much here that makes no sense or are red flags.

 

Additionally, my advice is that code  generally doesn't belong in datasets, which is another reason to explain more and another reason to consider a different process. And furthermore, I can't see a reason to store code in datasets that doesn't work at all because of imbalanced parentheses).

--
Paige Miller
Tom
Super User Tom
Super User

You seemed to have skipped explaining a lot of the steps here.

 

If you have macro variables that exist and you want to retrieve their values you can either just reference them.

my_ds_variable = "&my_macro_variable";

Or you could use SYMGET() function.  Which would work better for a lot of macro variables since the name could come from an expression.

length mvar $32 value $200;
do 1=1 to 3;
  mvar=cats('wtcalc',i);
  value = symget(mvar);
  output;
end;

Or just just reference SASHELP.VMACRO.

set sashelp.vmacro;
where name=: 'WTCALC' ;

If you really want to generate that strange macro variable you could do it like this (as long as the macro values do not exceed 200 bytes).

proc sql noprint;
select catx('=',name,value) into :logicx separated by ';%let '
  from dictionary.macros
  where name eqt 'WTCALC'
;
quit;
%let logicx=%nrstr(%let )%superq(logicx)%str(;) ;

If they do then perhaps use a data step instead so you can use SYMGET() to get the full value.

data _null_;
  length logicx $4000 ;
  retain logicx;
  set sashelp.vmacro end=eof;
  where name =: 'WTCALC' and offset=0;
  logicx=cats(logicx,catx(' ','%let',name),'=',symget(name),';');
  if eof then call symputx('logicx',logicx);
run;
%let logicx=%superq(logicx);

But why put this into a macro variable if the goal is to put it into data??

hellohere
Pyrite | Level 9

Thanks, Tom.

 

6784  %let wtcalc1= 0.2*weight;
6785  %let wtcalc2= 0.5*weight;
6786  %let wtcalc3= 0.8*weight;
6787
6788  data _null_;
6789    length logicx $4000 ;
6790    retain logicx;
6791    set sashelp.vmacro end=eof;
6792    where name =: 'WTCALC' and offset=0;
6793    logicx=cats(logicx,catx(' ','%let',name),'=',symget(name),';');
6794    if eof then call symputx('logicx',logicx);
6795  run;

NOTE: There were 3 observations read from the data set SASHELP.VMACRO.
      WHERE (name=:'WTCALC') and (offset=0);
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.01 seconds


6796  %let logicx=%superq(logicx);
6797
6798  %put "logic=&logicx.";
"logic=%let WTCALC1=0.2*weight;%let WTCALC2=0.5*weight;%let WTCALC3=0.8*weight;"

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

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
  • 10 replies
  • 271 views
  • 1 like
  • 7 in conversation