Macro variables created inside a macro can only be accessed within that macro (or by macros called by this macro). These macro variables do not have a value in open code (which is code outside of any macro).
You can fix this by adding a %GLOBAL statement into your macro.
%global age11;
By the way, I realize that this is probably just an example to learn macro code, but you really should never need to partition a data set this way by using macro loops, or extract information from a data set by using macro loops. There are better tools that are also easier to program with. Part of learning to use macros is learning when to NOT use macros.
Move the %PUT statement to inside the macro itself and you should see the value of the macro variable.
If you need the macro variables to continue to exist after the macro has finished running then you need to either create them before calling the macro or tell SAS make them in the GLOBAL symbol table instead of the symbol table of the currently running macro.
If you want to use SQL then add code to make the macro variable global when it does not yet exist.
%macro chk;
%local i j;
proc sql feedback noprint;
%do i=1 %to 5;
%do j=1 %to 2;
%if not %symexist(age&i.&j.) %then %global age&i.&j. ;
select distinct age into :age&i.&j. from class where n=&i. and m=&j.;
%end;
%end;
quit;
%mend;
Note the DISTINCT is not needed here since you did not include a SEPARTED BY clause the INTO will only put the first value of AGE into the macro variable.
If you switch to using a DATA step instead then you can use CALL SYMPUTX() which will allow to write directly into the GLOBAL symbol table.
data _null_;
set class;
where n in (1:5) and m in (1:2);
call symputx(cats('age',n,m),age,'G');
run;
But since with the data step code there is no need for %DO loops you probably do not even need to define the CHK macro. Which means you don't need to worry as much about where the macro variables are created.
Hi @Anv_SAS , I think this is what you wanted to achieve by the code you provided, however, you did not get what you desired. Here is my suggestion, please kindly let me know if it answer your question.
(1) you applied categories to the age and sex variables through the proc sort and merge steps, the code and output are as follows (in the output table, column n is age category and column m is sex category):
proc sort data=sashelp.class
out=class0 nodupkey;
by age;
run;
data class0;
set class0;
n=_n_;
run;
proc print data=class0;title "class0";run;
proc sort data=sashelp.class
out=class;
by age;
run;
proc print data=class;title "class";run;
data class2;
merge class(in=a)
class0(in=b keep=age n);
by age;
if a;
if sex="F" then m=1;
if sex="M" then m=2;
run;
proc print data=class2;title "class2";run;
(2) you were going to produce a macro variable which is the combination of the age and sex categories, and this macro variable resolves to respective students' names in the class as its' macro variable values. However, you did not choose the simple and efficient method to do this (you applied many techniques including macro, sql, nested do loop, which made the code difficult to debug). Here is my thinking and suggestion: you can simply use a single sql or data _null_ step to produce this macro variable.
proc sql;
select name,n,m
into :name1-,:n1-,:m1-
from class2;
quit;
%put _user_;
data _null_;
set class2;
call symputx(name,cat(n,m));
run;
%put _user_;
data _null_;
set class2;
call symputx(cat('age',n,m),name);
run;
%put _user_;
86 %put _user_; GLOBAL AGE11 Joyce GLOBAL AGE12 Thomas GLOBAL AGE21 Louise GLOBAL AGE22 Robert GLOBAL AGE31 Barbara GLOBAL AGE32 Jeffrey GLOBAL AGE41 Judy GLOBAL AGE42 Henry GLOBAL AGE51 Mary GLOBAL AGE52 William GLOBAL AGE62 Philip GLOBAL ALFRED 42 GLOBAL ALICE 31 GLOBAL BARBARA 31 GLOBAL CAROL 41 GLOBAL HENRY 42 GLOBAL JAMES 22 GLOBAL JANE 21 GLOBAL JANET 51 GLOBAL JEFFREY 32 GLOBAL JOHN 22 GLOBAL JOYCE 11 GLOBAL JUDY 41 GLOBAL LOUISE 21 GLOBAL M1 1 GLOBAL M10 2 GLOBAL M11 2 GLOBAL M12 1 GLOBAL M13 2 GLOBAL M14 1 GLOBAL M15 1 GLOBAL M16 1 GLOBAL M17 2 GLOBAL M18 2 GLOBAL M19 2 GLOBAL M2 2 GLOBAL M3 2 GLOBAL M4 1 GLOBAL M5 2 GLOBAL M6 1 GLOBAL M7 2 GLOBAL M8 1 GLOBAL M9 1 GLOBAL MARY 51 GLOBAL N1 1 GLOBAL N10 3 GLOBAL N11 4 GLOBAL N12 4 GLOBAL N13 4 GLOBAL N14 4 GLOBAL N15 5 GLOBAL N16 5 GLOBAL N17 5 GLOBAL N18 5 GLOBAL N19 6 GLOBAL N2 1 GLOBAL N3 2 GLOBAL N4 2 GLOBAL N5 2 GLOBAL N6 2 GLOBAL N7 2 GLOBAL N8 3 GLOBAL N9 3 GLOBAL NAME1 Joyce GLOBAL NAME10 Jeffrey GLOBAL NAME11 Alfred GLOBAL NAME12 Carol GLOBAL NAME13 Henry GLOBAL NAME14 Judy GLOBAL NAME15 Janet GLOBAL NAME16 Mary GLOBAL NAME17 Ronald GLOBAL NAME18 William GLOBAL NAME19 Philip GLOBAL NAME2 Thomas GLOBAL NAME3 James GLOBAL NAME4 Jane GLOBAL NAME5 John GLOBAL NAME6 Louise GLOBAL NAME7 Robert GLOBAL NAME8 Alice GLOBAL NAME9 Barbara GLOBAL PHILIP 62 GLOBAL ROBERT 22 GLOBAL RONALD 52
(3) to conclude, the last data _null_ step might be the solution, which produces desired result and the macro variable &age11 was correctly resolved to a class student's name, Joyce, the code and results is as follows.
data _null_;
set class2;
call symputx(cat('age',n,m),name);
run;
%put &age11;
69 data _null_; 70 set class2; 71 call symputx(cat('age',n,m),name); 72 run; NOTE: There were 19 observations read from the data set WORK.CLASS2. 73 %put &age11; Joyce
Thanks all, for helping in fixing the issue. As mentioned by Paige Miller, I have added %global statement and issue fixed. Also I have deleted those global macro variables using %symdel statement. My requirement is to pull pool of records into a single macro variable conditionally. And finally chopping them into individual records again using SCAN. To avoid overwriting of original files, I used SASHELP.ClASS to test the logic. As Paige Miller suggested we have different non-macro methods as well which can fit in. Once again Thanks all for your valuable solutions 🙂
My requirement is to pull pool of records into a single macro variable conditionally.
Data from several (many) records does not belong in a macro variable. It belongs in a SAS data set. Please explain your project in more global terms, do not talk about SAS code, but do talk about what the data is and how will you use of the data once you pull it.
Hi Paige Miller, I work on a study and I was instructed to generate Cartesian Product from 2 datasets applying 2 filter conditions, to ensure the respective records only needs to be used. Also I was instructed not to use direct Cartesianing techniques like PROC SQL or DATA step POINT statement. I tried this using PROC SQL macro variables creation method (PROC SQL; select records into :rec_&i.&j from <dataset> where <var1>=1 and <var2>=1;quit ). However, we have many values in 2 filter variables, due to which I need to write many PROC SQL steps in OPEN code. So I thought I could create a macro to iterate the nested loop.
%macro rec_list;
%do i=1 %to 3;
%do j=1 %to 4;
proc sql;
select records into :rec_list_&i.&j. seperated by " " from ABC where VAR1=&i AND VAR2=&j;
select count(*) into :n_list_&i.&j. from ABC where VAR1=&i AND VAR2=&j;
quit;
%end;
%end;
%mend;
%rec_list;
%put &rec_list_11.;
On running above code macro variables are generated but I could not see macro variables resolving.
After I use %global statement, I can see macro variables resolving and I deleted them using %symdel at last of the pgm to avoid confusion or overwriting of Global Macro variables.
@Anv_SAS wrote:
Hi Paige Miller, I work on a study and I was instructed to generate Cartesian Product from 2 datasets applying 2 filter conditions, to ensure the respective records only needs to be used. Also I was instructed not to use direct Cartesianing techniques like PROC SQL or DATA step POINT statement.
Okay. Thank your for the explanation. I feel sorry for you, that you have been told to do something but you can't use tools specifically designed to perform the desired task. Its like telling a carpenter that he can't use a saw or telling a plumber he can't use a wrench.
Still, it is highly recommended that you mention the goal at the beginning (for this thread and for all future threads) instead of not mentioning it. Perhaps if people knew you were trying to create Cartesian product with macro variables, a brilliant idea would pop into someone's head that would get you there quickly (and there are a lot of people who do have brilliant ideas in this forum).
Anyway, I will drop out of this discussion now, as I do not care to hurt my brain creating Cartesian products using macro variables. Best wishes and good luck.
Why did you write it as two separate macros? If you made the macro variables inside the same macro that used them you could instead make them LOCAL and not have to worry about deleting them since they would disappear when the macro finished.
The issue that should be fixed is the creation of 10 macro variables.
So: what do you want to do after macro chk?
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
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.
Ready to level-up your skills? Choose your own adventure.