Hi,
I am stuck into some real time situation, every month I get a notepad file without headers and I do use proc import to get the data in SAS dataset. Now in this notepad there are so many fields(aprox 500) so proc import give the variable names as Var1 Var2 ...Var500
So once I have created the dataset , now I rename the variables starting from var24.
so the pattern is somehting like in one varibale lets say in var22 I get a date, lets say it start date then I need to trac data for 24 months back.
Example- lets say in var22 I have date - 13-Oct-2016
now I will rename the vars starting from var24 like this.
Rename(
var24=V_10_13_2016
Var25=V_10_06_2016
Var26=V_09_30_2016
Var27=V_09_23_2016
Var28=V_09_16_2016
Var27=V_09_09_2016
...................................
till 24 months.
Now if you see the pattern we go back 7 days but if that changes the month then we stop at the last day of the month, see above
Var25=V_10_06_2016
Var26=V_09_30_2016
Now If I can write a macro to create such string Var27=V_09_09_2016 like this then my task will be easy and I can redduce my work hrs.
Please help me in here. Thanks
I posted you such macro name REN_VARS geting 3 arguments:
(1) v2start = 24 as you wanted to rename from var24 on
(2) v2end = 40 as you said that your last var to rename is var40
(3) from_date = 13-OCT-2016 as you computed dates startin with OCT 13th, 2016
going backwards (to the past) decresing 7 days except when mont changes then last day in month.
The macro REN_VARS creates a string like:
var24=V_10_13_2016 var25=V_10_06_2016 var26=V_09_30_2016 ... etc
The result will be in a macro variable named ren_all to be used as:
data want;
set mydataset (rename=( &ren_all));
...
run;
Adapt next macro/code to your needs:
%macro ren_vars(v2start=24,
v2end=40,
from_date=13-Oct-2016);
data _null_;
length ren_all $10000 renx $25 datex $10;
datex = compress("&from_date",'-')||'d';
from_date = input(datex,date9.); *put from_date=;
vnum = &v2start;
varx = "var&v2start";
do until (vnum = &v2end);
datex = put(from_date,mmddyy10.);
renx = cat(varx,' = ',"v_",datex); *put renx=;
ren_all = trim(ren_all) ||' '|| renx;
if day(from_date) > 7 then from_date = from_date - 7;
else from_date = intnx('month',from_date,-1,'e');
vnum+1;
end;
call symput('ren_all',trim(ren_all));
run;
%put ren_all=&ren_all; /* check results in the log */
%mend ren_vars;
%ren_vars(v2start=24,
v2end=40, /* addapt to needs, 500 ? */
from_date=13-Oct-2016);
I feel that instead of creating logic to rename the variables, you should be trying to come up/ask for logic to transpose your data from a wide into a long structure. That could make things quite a bit easier.
It would also help a lot if you could post some representative sample data.
If the file is supposed to be in the same format then you should only use proc import one time. Proc import when reading text files will create data step code to read the file. Look in the log after importing one of these files to see the code. Copy it from the Log to an editor and make needed changes such as specifying the variable names, double checking on informats to maintain consistent types and lengths of character variables and possibly adding labels. Then you only need to change the name of the input file and output data set.
If you continually use Proc Import you will with very high probability end up with variables of different types, numeric and text, or different length character variables.
If the file format changes then it still may be easier to create incremented code to read the desired variables it just adds a step for you to tell the program the start end dates.
Note that if the data was actually in long form:
Date Value instead of having a separate column for each value the data would be much easier to handle in the long run.
So here is what i do everyday.
Firrt run Proc Import and get the text file in SAS.
Proc import datafile="File.txt" out=mydataset
dbms=dlm replace;
delimiter=";";
getnames=no;
run;
Data want;
set mydataset(rename=
(
ar24=V_10_13_2016
Var25=V_10_06_2016
Var26=V_09_30_2016
Var27=V_09_23_2016
Var28=V_09_16_2016
Var27=V_09_09_2016
/*for all 500 vars */)
run;
now want data is ready for me to work.
So I was trying to create a macro so that I can replace that I can call my macro
rename=(%mymacro);
Please help me in here.
Thanks!
I posted you such macro name REN_VARS geting 3 arguments:
(1) v2start = 24 as you wanted to rename from var24 on
(2) v2end = 40 as you said that your last var to rename is var40
(3) from_date = 13-OCT-2016 as you computed dates startin with OCT 13th, 2016
going backwards (to the past) decresing 7 days except when mont changes then last day in month.
The macro REN_VARS creates a string like:
var24=V_10_13_2016 var25=V_10_06_2016 var26=V_09_30_2016 ... etc
The result will be in a macro variable named ren_all to be used as:
data want;
set mydataset (rename=( &ren_all));
...
run;
Thanks Shmuel, this is what I was looking towards, I am working on your code to make it work for me for all
rest of the vars.
your help highly appreciated.
Hi Shmuel,
I am trying to run your code and the result I am getting is like this
var24 = v_10/13/2016 var24 = v_10/06/2016 var24 = v_09/30/2016 var24 = v_09/23/2016......
but if you see var24 is costant and date should be in underscore separated not by '/';
so desired output should be like this
var24 = v_10_13_2016 var25 = v_10_06_2016 var26 = v_09_30_2016 var27 = v_09_23_2016....
Please help me in here.
Thanks
Sorry, I was too buisy last days.
The rename you got:
var24 = v_10/13/2016
is the result of line (in the macro)
datex = put(from_date,mmddyy10.);
Just add next line after it, inside the macro:
datex = translate(datex , '_' , '/');
to get the desired format:
var24 = v_10_13_2016
Hey Shmuel,
I had created the macro and it's working fine but there is a slite change is output I require, I tried so many things but this is not working so I need ur help in here..
I have written this code-
/* is how I get date part, its okay I can deal with this*/
data _null_;
date1="071016";
dd=substr(date1,1,2);
mm=substr(date1,3,2);
yy=substr(date1,5,2);
datex=mdy(mm,dd,yy);
call symputx("from_date",datex,'G');
run;
/* now I have got the date I will above date to start creating my values */
%macro ren_vars;
data _null_;
length NRx $10000 renx $25 datex $10;
datex = compress("&from_date");
from_date = input(datex,10.);
format from_date mmddyy10.;
do vnum=24 to 151;
datex = put(from_date,mmddyy10.);
renx = cat("Var",vnum,' = ',"NRx_",datex);
renx=tranwrd(renx,"/","_");
NRx = trim(NRx) ||' '|| renx;
if day(from_date) > 7 then from_date = from_date - 7;
else from_date = intnx('month',from_date,-1,'e');
end;
call symputx('NRx',trim(NRx),'G');
run;
%put ------------------Nrx-------------------------------------;
%put &NRx;
%mend ren_vars;
%ren_vars;
look at the output I am getting--- few lines of output shown below
Var24 = NRx_10_07_20-16 Var25 = NRx_09_30_2016 Var26 = NRx_09_23_2016 Var27 = NRx_09_16_2016
Var28 = NRx_09_09_2016 Var29 = NRx_09_02_2016 Var30 = NRx_08_31_2016 Var31 = NRx_08_24_2016
Var32 = NRx_08_17_2016 Var33 = NRx_08_10_2016 Var34 = NRx_08_03_2016 Var35 = NRx_07_31_2016
Var36 = NRx_07_24_2016 Var37 = NRx_07_17_2016 Var38 = NRx_07_10_2016 Var39 = NRx_07_03_2016
Var40 = NRx_06_30_2016 Var41 = NRx_06_23_2016 Var42 = NRx_06_16_2016 Var43 = NRx_06_09_2016
what I want this is when it reaches to end of the month logic like we are checking if day>7 then keep substratcing 7 days from from_date but if day is <7 then that means it's going to next month so what we are asking system to go end of prev month and
start over doing that -7 day logic but i want here that our code should split the 7 days logic if u look at the above code in line 2
Var29 = NRx_09_02_2016 Var30 = NRx_08_31_2016 Var31 = NRx_08_24_2016
when our code came at 2nd day it found that ohh ok now this is less than 7 means go to end of pev month till this we are fine
Var30 = NRx_08_31_2016 but now Var31 should only substract 5 days and should give result as Var31=NRx_08_26_2016
so if you look colsely from 09-02 to 08-31 two days and then from 08-31 to 08-26 five days total comes 7 days
this is what I said split week, I am not able to find out logic , pls guide.
below are the sample output to make u better understand the output which I am looking for---
----want----
Var24=NRx_10_07_2016 Var25=NRx_09_30_2016 Var26=NRx_09_23_2016 Var27=NRx_09_16_2016 Var28=NRx_09_09_2016
Var29=NRx_09_02_2016 Var30=NRx_08_31_2016 Var31=NRx_08_26_2016 Var32=NRx_08_19_2016 Var33=NRx_08_12_2016
Var34=NRx_08_05_2016 Var35=NRx_07_31_2016 Var36=NRx_07_29_2016 Var37=NRx_07_22_2016 Var38=NRx_07_15_2016
Var39=NRx_07_08_2016 Var40=NRx_07_01_2016 Var41=NRx_06_30_2016 Var42=NRx_06_24_2016 Var43=NRx_06_17_2016
Var44=NRx_06_10_2016 Var45=NRx_06_03_2016 Var46=NRx_05_31_2016 Var47=NRx_05_27_2016 Var48=NRx_05_20_2016
1) Pay attention, MDY function creates a numeric sas date variable containing
the number of days past since January 1st, 1960 up to given date.
You can shorten 1st step to:
data _null_;
datex = input("07102016",ddmmyy10.) ;
/* or datex = '07OCT2016'd; */
call symputx("from_date",strip(datex),'G');
run;
2) As from_date is a number you can make your code more simple:
instead:
%macro ren_vars;
data _null_;
length NRx $10000 renx $25 datex $10;
datex = compress("&from_date");
from_date = input(datex,10.);
you better use:
%macro ren_vars;
data _null_;
length NRx $10000 renx $25 datex $10;
from_date = &from_date;
3) As to splitting 7 days when changing month:
instead
do vnum=24 to 151;
datex = put(from_date,mmddyy10.);
renx = cat("Var",vnum,' = ',"NRx_",datex);
renx=tranwrd(renx,"/","_");
NRx = trim(NRx) ||' '|| renx;
if day(from_date) > 7 then from_date = from_date - 7;
else from_date = intnx('month',from_date,-1,'e');
end;
you need:
do vnum=24 to 151;
datex = put(from_date,mmddyy10.);
renx = cat("Var",vnum,' = ',"NRx_",datex);
renx=tranwrd(renx,"/","_");
NRx = trim(NRx) ||' '|| renx;
if day(from_date) > 7 then from_date = from_date - 7;
else do;
diff = day(from_date);
from_date = intnx('month',from_date,-1,'e');
datex = put(from_date,mmddyy10.);
renx = cat("Var",vnum,' = ',"NRx_",datex);
renx=tranwrd(renx,"/","_");
NRx = trim(NRx) ||' '|| renx;
if vnum = 151 then leave;
vnum = vnum +1;
from_date = from_date - 7 + diff;
end;
end;
DROP diff;
It would seem to me that you should just skip the PROC IMPORT and just read your data file directly.
Can you explain the data structure in more detail?
So column 22 has the date? And column 24 onward are values for follow-up dates that are based on that starting date? Does that extend to the end of the line?
What do the first 21 columns contain?
What does column 23 contain?
What happens on the next observation? Is column 22 the same for every row in the source file? If not then your RENAME method is bound to fail.
What structure would you like for the data? I would assume that it would make much more sense to have a series of observations with DATE/VALUE pairs instead of putting the date information into the NAME of the variable.
How are you going to use the data?
Hi Tom,
I really apriciate your intrest into this so here are the answers of your questions
Does that extend to the end of the line? yes from 24 to 535 vars
set of three group of vars var24 to var151 and var152 to v279 and (next two set of 127 vars in each ).....till 535
What do the first 21 columns contain? these are Client_Number,Report_Number,Prescriber_ID.. etc.... and these are fixed so I can easly rename this and they never change in any file we receive from client.
What does column 23 contain? Maximum_Number_of_Buckets
so data structure is something like
var1 to var23 constant var names and from var24 to var 535 each of 127 set of vars
will have date values like I said going back 7 days from start date(var22) and if next month then end of month.
hope this will help
thanks!
Sounds like you can just write a single data step to read the file.
The program could look something like this. Fill in the names and types for the rest of the first 23 variables and attach any informats or formats that they need (don't attach formats that they don't need). Make some more meaningful variable names for your three arrays of readings.
data want ;
infile 'myfile' dsd dlm=';' truncover ;
length Client_Number $10
Report_Number $12
...
Report_Date 8
Maximum_Number_of_Buckets 8
;
informat Report_Date date9. ;
format Report_Date Date date9. ;
array A (127);
array B (127);
array C (127);
input Client_Number -- Maximum_Number_of_Buckets a1-a127 b1-b127 c1-c127;
previous = Report_Date ;
do i=1 to Maximum_Number_of_Buckets ;
date = intnx('day',previous,-7) ;
if month(date) ne month(previous) then date=intnx('month',date,0,'end');
reading1 = a(i);
reading2 = b(i);
reading3 = c(i);
output;
previous = date;
end;
drop a1-a127 b1-b127 c1-c127 previous i ;
run;
This is assuming that the values are aligned into the 127 cells. So if there are 3 buckets you have 3 values then 124 empty values then 3 values etc. If instead the empty cells are all at the end so that you have A,A,A,B,B,B,C,C,C,.,.,. then just use one array and calculate where to find the right values.
reading1 = a(i);
reading2 = a(Maximum_Number_of_Buckets + i);
reading3 = a(2*Maximum_Number_of_Buckets + i);
This is going to be much easier to do with a DATA step than macro code.
Let's make a simple example dataset that has VAR22 and some other variables.
data have ;
var22 = '13oct2016'd ;
length var24 - var200 8 ;
run;
Now let's write a DATA _NULL_ step to write out a RENAME statement into a text file. I have adjusted it to use YYYY-MM-DD format instead of MM-DD-YYYY format because then the variable names will sort alphabetically into the proper order.
filename code temp;
data _null_;
file code ;
set have (obs=1 keep= var22);
put 'rename ' ;
previous = var22;
date = var22;
format var22 previous date YYMMDD10. ;
length varname newname $32 ;
do i=24 by 1 ;
varname=cats('var',i);
date = intnx('day',previous,-7);
if month(date) ^= month(previous) then date=intnx('month',date,0,'end');
if (date <= intnx('month',var22,-24)) then leave ;
newname = 'V_' || translate( put(date, yymmdd10.) , '_','-') ;
put varname '=' newname ;
previous=date ;
end;
put ';' ;
run;
Then you can just %INCLUDE that statement where you need it.
data want ;
set have ;
%inc code / source2 ;
run;
Results
106 data want ; 107 set have ; 108 %inc code / source2 ; NOTE: %INCLUDE (level 1) file CODE is file /.../#LN00013. 109 +rename 110 +var24 =V_2016_10_06 111 +var25 =V_2016_09_30 112 +var26 =V_2016_09_23 113 +var27 =V_2016_09_16 114 +var28 =V_2016_09_09 115 +var29 =V_2016_09_02 116 +var30 =V_2016_08_31 117 +var31 =V_2016_08_24 118 +var32 =V_2016_08_17 119 +var33 =V_2016_08_10 120 +var34 =V_2016_08_03 121 +var35 =V_2016_07_31 122 +var36 =V_2016_07_24
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: