Hi I'm trying to dynamically change a name of a variable being used in some if/then statements based upon the observation line information.
Data Structure
Patient_ID | Admit_date | Member_200801 | …(to)…. | Member_200812 |
1 | 1/1/2008 | 1 | 0 | |
1 | 11/2/2008 | 1 | 0 | |
2 | 4/5/2008 | 0 | 0 | |
3 | 12/10/2008 | 0 | 1 | |
3 | 6/8/2008 | 1 | 0 |
What I'd like to do is based upon the admission date, reference the correct membership variable to see if they were eligible (0/1). I've tried using the symput and symputx to pull the date from the observational information, which it has, but only for the last observation in my data.
data merged1;
set merged;
call symput('check',put(admit_date,yymmn6.));
if Member_&check = 1 then elig=1;
run;
%put var=✓
When I run this code above, it does assign a date to &check but its the last observation of my data set but that's not relevant to each individual patient in my data. Any help would be great. Thanks!
If I understand your task correctly, you'd be better served by declaring a 2 dimensional array with variable names
member_200801 member_200802 .... member_200812 member_200901 .... member_200912 (assuming you have a two year range covering 2008 and 2009). The 1st dimension of the array is the year, the 2nd is the month. Then using the year and month functions inside to establish array row and column will pinpoint the desired variable:
data want;
set have;
array membs {2008:2009,12}
member_200801-member_200812
member_200901-member_200912;
if membs{year(admit_date),month(admit_date)}=1 then elig=1;
run;
The array above has 2 rows (2008 and 2009) and 12 columns (1 through 12).
And if you only have one year, then a one-dimensional array:
data want;
set have;
array membs {12} member_200801-member_200812
if membs{month(admit_date)}=1 then elig=1;
run;
No need for macro, single pass of the data.
SAS data steps have a compilation and a execution phase. All variables get defined in the compilation phase and though it's not possible to dynamically introduce new variables during data step execution.
Macro variables resolve before the data step gets compiled so they just allow you to dynamically write data step code BEFORE the SAS compiler then picks up this code (at this point the code is static). That's why what you're trying to do can't work.
Having the data in this wide instead of a long structure makes this simple task ridiculously difficult. But here you go.
data have;
format admit_date date9.;
member_200801='1';
member_200805='0';
admit_date='01jan2008'd;
output;
admit_date='15may2008'd;
output;
stop;
run;
data want(drop=_:);
/* map variables */
if 0 then set have;
/* define array for variables member_.... */
array members {*} member_:;
/* define and load hash with name and index number of array elements */
if _n_=1 then
do;
length _el_name $32 _el_index 8;
dcl hash h1(hashexp:3);
h1.defineKey('_el_name');
h1.defineData('_el_index');
h1.defineDone();
do _i=1 to dim(members);
h1.add(key:upcase(vname(members(_i))), data:_i);
end;
end;
call missing(of _all_);
set have;
/* find index number of array element with the required data */
_rc=h1.find(key:cat('MEMBER_',put(admit_date,yymmn6.)));
/* populated elig with the value from the identified array element */
if not missing(_el_index) then elig=members[_el_index];
run;
Using a hash to find the required array element avoids the need to loop for every row over the array to find the array element with the required name.
It's more complex than that unfortunately.
Here's one way:
*Assumptions: *You have a date for every month, if not you may have missing months *you likely want to collapse an ID to a single record per ID *you have more than one year of data ; data have; format admit_date date9.; id=1; admit_date='01jan2008'd; output; admit_date='01Nov2008'd; output; admit_date='01jan2009'd; output; admit_date='01Nov2010'd; output; id=2; admit_date='15may2008'd; output; admit_date='15Dec2008'd; output; admit_date='15may2009'd; output; admit_date='15Dec2010'd; output; run; data want; set have; by id; array member(2008:2010, 1:12) /*Use a two dimensional array and index array with year/month*/ member_2008_1-member_2008_12 member_2009_1-member_2009_12 member_2010_1-member_2010_12 (36*0) /*initialize to 0, implicit retain*/; *if first ID set all to 0, to prevent previous ID carrying over; if first.id then do; do year=2008 to 2010; do month=1 to 12; member(year, month)=0; end; end; end; *determine year/month, could next directly into member assignment; year=year(admit_date); month=month(admit_date); *Assign 1 to the appropriate year/month; member(year, month)=1; *output only when last record for person; if last.id then output; run;
@endofline wrote:
Hi I'm trying to dynamically change a name of a variable being used in some if/then statements based upon the observation line information.
Data Structure
Patient_ID Admit_date Member_200801 …(to)…. Member_200812 1 1/1/2008 1 0 1 11/2/2008 1 0 2 4/5/2008 0 0 3 12/10/2008 0 1 3 6/8/2008 1 0
What I'd like to do is based upon the admission date, reference the correct membership variable to see if they were eligible (0/1). I've tried using the symput and symputx to pull the date from the observational information, which it has, but only for the last observation in my data.
data merged1;
set merged;
call symput('check',put(admit_date,yymmn6.));
if Member_&check = 1 then elig=1;
run;
%put var=✓
When I run this code above, it does assign a date to &check but its the last observation of my data set but that's not relevant to each individual patient in my data. Any help would be great. Thanks!
If I understand your task correctly, you'd be better served by declaring a 2 dimensional array with variable names
member_200801 member_200802 .... member_200812 member_200901 .... member_200912 (assuming you have a two year range covering 2008 and 2009). The 1st dimension of the array is the year, the 2nd is the month. Then using the year and month functions inside to establish array row and column will pinpoint the desired variable:
data want;
set have;
array membs {2008:2009,12}
member_200801-member_200812
member_200901-member_200912;
if membs{year(admit_date),month(admit_date)}=1 then elig=1;
run;
The array above has 2 rows (2008 and 2009) and 12 columns (1 through 12).
And if you only have one year, then a one-dimensional array:
data want;
set have;
array membs {12} member_200801-member_200812
if membs{month(admit_date)}=1 then elig=1;
run;
No need for macro, single pass of the data.
The macro processor just generates text that is then used by SAS just as if you had originally typed it that way. The macro processor cannot travel backwards in time. It cannot change the code of a data step after it has been compiled and started running.
There is no need to do anything dynamic for your problem. Just use an ARRAY. Calculate the index into the array based on the value or your date variable.
array member member_201801 ..... ;
index=intck('month','01JAN2018'd,admit_date)+1;
if 1 <= index <= dim(member) then elig=member(index);
If you did want to try something "dynamic" then looking into using one of the functions with X as the last letter. In this case the VVALUEX() function which can find the value of variable whose name can be the result of an expression.
elig = input(vvaluex(cats('member_',put(admit_date,yymmn6.))),32.);
Here is another way using Transpose and SAS functions.
data have;
format date mmddyy10.;
input patient date mmddyy10. mem_200801 mem_200802 mem_200803 mem_200804;
datalines;
1 01/01/2008 1 0 0 0
2 02/01/2008 0 1 0 0
3 03/01/2008 0 0 0 0
4 04/01/2008 0 0 0 1
;
run;
proc transpose data=have out=trans_have prefix=new;
by patient date;
run;
data trans_have_mod;
set trans_have;
if put(date,yymmn6.)=strip(scan(_name_,2,'_')) and new1=1 then elig=1;
if elig=1;
drop _name_ new1;
run;
data want;
merge have trans_have_mod;
by patient date;
run;
Just a note, that if you use @SuryaKiran solution if a month is not in the data it will not be in the columns. If you need a record for every month you'll have to add that in somehow.
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 16. 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.
Select SAS Training centers are offering in-person courses. View upcoming courses for: