Is there a way in SAS 9.2 to dynamically change a Global variable within a SAS macro e.g.
%Global testVar;
%macro Test(variableToChange);
%let variableToChange = “A”;
%mend;
%Test(testVar);
Very close ... need to add an ampersand:
%let &variableToChange = "A";
It's not clear that you want quotes as part of the new value ... your example will change the variable to a set of three characters where the second character is A and the first and third characters are quotes.
Also, the local symbol table must not contain a macro variable named testVar. If it does, the local version will be changed not the global version.
Very close ... need to add an ampersand:
%let &variableToChange = "A";
It's not clear that you want quotes as part of the new value ... your example will change the variable to a set of three characters where the second character is A and the first and third characters are quotes.
Also, the local symbol table must not contain a macro variable named testVar. If it does, the local version will be changed not the global version.
Is there a way for a SAS macro to return a value? I found some documentation that looked like the below. Where the paper left the semi-colon off but it didn’t work for me in SAS 9.2.
%macro Test(variableToChange);
%let variableToChange = ‘A’;
&variableToChange /*this would be returned??*/
%mend;
This time you need to add two ampersands. The text to be returned should be:
&&&variableToChange
&variableToChange resolves to TextVar. Adding the two ampersands resolves to the value of &TextVar.
Is it good practice to do this however? The term Global means the whole program, to change that within a specific section seems to defeat the purpose. Take an example:
%global pi;
%let pi=3.14;
%macro print();
proc print ...;
%let pi=3.141;
%mend print;
%Check_Circle_Measurements();
%Print();
%Check_Circle_Measurements();
...
The print changes the calculation later on. Ok, with this you can see that, but if you have several files included, would you not lose confidence in the fact that pi had changed? This is one of the old obfuscation techniques, change something which appears to be one thing into another in a subtle manner so its hard to see.
%let &variableToChange = “A”; worked for me on a simple scenario. I tried using the same logic in a more complex macro and found that I’m running into an error on
%let &spacedList = &spacedList.%scan(%superQ(commaList), 1, str(,));
Where this works.
%let degStudLev = °StudLev.%scan(%superQ(degStudLevComma), 1, str(,));
The full examples are below. I’m thinking that I need to enclose commaList with something.
/*outputs degStudLevdegS (Weird Output)*/
%Macro convertCommaListToSpaced(commaList, spacedList);
%let &spacedList = &spacedList.%scan(%superQ(commaList), 1, str(,));
%mend;
%macro testmacro3();
%let degStudLevComma = AH,AX,AV,AI;
%let degStudLev= %str();
%convertCommaListToSpaced(degStudLevComma, degStudLev);
%put °StudLev;
%mend;
%testmacro3;
/*outputs AH (Good Output)*/
%Macro convertCommaListToSpaced(commaList, spacedList);
%let degStudLevComma = AH,AX,AV,AI;
%let degStudLev= %str();
%let degStudLev = °StudLev.%scan(%superQ(degStudLevComma), 1, str(,));
%mend;
%macro testmacro3();
%convertCommaListToSpaced(degStudLevComma, degStudLev);
%put °StudLev;
%mend;
%testmacro3;
A little simpler example of the problem.
This produces: degStuLevComma.
/*outputs degStuLevComma*/
%Macro convertCommaListToSpaced(commaList, spacedList);
%let test = A;
%put &commaList;
%mend;
%macro testmacro3();
%let degStudLevComma = AH,AX,AV,AI;
%let degStudLev= %str();
%convertCommaListToSpaced(degStudLevComma, degStudLev);
%mend;
%testmacro3;
I found I can use this:
%let degStudLev = %convertCommaListToSpaced(commaList =%str(%quote(°StudLevComma)), spacedList =°StudLev);
Still my result is not equivalent to running this without the macro.
Sorry to sound like a broken record, but the examples you have given above would be far simpler to put lists of options in datasets rather than trying to force macro language to do base language processing.
data list;
val="A"; output;
val="B"; output;
val="C"; output;
run;
/* Use list in base code */
proc sql;
create table WANT as
select * from HAVE where ID in (select VAL from LIST);
quit;
/* Use list to create where list */
proc sql;
select VAL into :V_LIST separated by " "; /* Just change if you want commas */
quit;
data want;
set have (where=(id in (&V_LIST.));
run;
Etc. The above seems far simpler to me that all that %xyz(&&&ABC&&&YYX%something());
RW9,
The input format is A,B,C.
Step 1 requires format A B C
Step 2 requires ‘A’, ‘B’, ‘C’
I need the macro to convert the input format to at least step 1.
I also need to run this logic on 20 different inputs at different parts of the stored process.
Not sure what you mean by "input" as don't use stored processes, but:
data _null_;
set input;
call symput('step1',tranwrd(input,","," "));
call symput('step2',"'"||tranwrd(input,",","','")||"'");
run;
Should do it.
Registration is open! SAS is returning to Vegas for an AI and analytics experience like no other! Whether you're an executive, manager, end user or SAS partner, SAS Innovate is designed for everyone on your team. Register for just $495 by 12/31/2023.
If you are interested in speaking, there is still time to submit a session idea. More details are posted on the website.
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.