How would I run a macro on a list of variables one at a time, without the macro reading all of them at once? In this example, I am also trying to merge individual datasets back together based on the var list.
This code doesn't work:
%let vars =
f15_specimen
f15_albumin_month
f15_albumin_year
f15_albumin_g;
*Create individual datasets named by the variable;
%macro variable;
data &vars; set f15_long;
keep thesubjectid zvisitdate_lab &vars;
if &vars=. then delete;
run;
proc sort data= &vars; by thesubjectid zvisitdate_lab; run;
proc sort nodupkey data= &vars; by thesubjectid; run;
data all;
merge &vars;
by thesubjectid;
run;
%mend;
The idea is to select the first non-missing datapoint from each variable per SubjectID. Here I'm using the long-form data; I have also attempted this problem within an array on wide-form data (ie. f15_specimen1-f15_specimen40), but succeeded only in selecting the last non-missing datapoint instead of the first. So a solution using an array could work, although I would like to know how to work with lists in macros.
Thanks!
How about this?
%let vars = age height ;
%macro variable();
%do i = 1 %to 2;
%let new_var = %scan(&vars., &i.," ");
data &new_var.;
set sashelp.class;
if &new_var. = . then delete;
run;
proc sort data = &new_var.;by name;run;
%end;
%mend variable;
%variable;
data all;
merge &vars.;
by name;
run;
let me know if this works.
Good luck!
Anca.
Show example data and what you want the result to look like. Don't worry about macro variables lists just yet.
You can find the data points you need without processing the variables one at a time.
Show example data.
The macro list example worked, but to answer your question data_null, in case you have a simpler solution (and if one didn't want to go through creating separate datasets for each variable), the data look like this:
Long form:
Obs thesubjectid zvisitdate_lab f15_specimen
1 10 2005 2
2 100
3 100 2006 4
4 100 2006 5
5 100 2007 6
Wide form:
Obs thesubjectid zvisitdate_lab1 zvisitdate_lab2 zvisitdate_lab3 zvisitdate_lab4 f15_Specimen1 f15_Specimen2 f15_Specimen3 f15_Specimen4
1 10 2005 2
2 100 . 2006 2006 2007 . 4 5 6
Need the first non-missing datapoint per subject for each variable:
Obs thesubjectid zvisitdate_lab f15_Specimen
1 10 2005 2
2 100 2006 4
This code worked on the wide-form data in an array on one variable at a time with the "leave" command, but I haven't worked out how that might look inside a macro.
data tests; set f15;
keep thesubjectid specimen f15_specimen1-f15_specimen40;
specimen=.;
array spec(40) f15_specimen1-f15_specimen40;
do i=1 to 40;
if spec(i)^=. then do; specimen=spec(i); leave; end; end;
run;
How about this?
%let vars = age height ;
%macro variable();
%do i = 1 %to 2;
%let new_var = %scan(&vars., &i.," ");
data &new_var.;
set sashelp.class;
if &new_var. = . then delete;
run;
proc sort data = &new_var.;by name;run;
%end;
%mend variable;
%variable;
data all;
merge &vars.;
by name;
run;
let me know if this works.
Good luck!
Anca.
Thanks, it looks like the %do and %scan lines did the trick for the list method!
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.