DATA Step, Macro, Functions and more

Generate strings using macro

Accepted Solution Solved
Reply
Contributor
Posts: 37
Accepted Solution

Generate strings using macro

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

 

 


Accepted Solutions
Solution
‎12-06-2016 06:29 AM
Trusted Advisor
Posts: 1,574

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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;

View solution in original post


All Replies
Trusted Advisor
Posts: 1,574

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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);
             
Respected Advisor
Posts: 4,173

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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.

Super User
Posts: 11,343

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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.

Contributor
Posts: 37

Re: Generate strings using macro

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!

 

Solution
‎12-06-2016 06:29 AM
Trusted Advisor
Posts: 1,574

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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;

Contributor
Posts: 37

Re: Generate strings using macro

Thanks 

 

 

Contributor
Posts: 37

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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

Trusted Advisor
Posts: 1,574

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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

Contributor
Posts: 37

Re: Generate strings using macro

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

Trusted Advisor
Posts: 1,574

Re: Generate strings using macro

[ Edited ]
Posted in reply to LittlesasMaster

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;

 

 

Super User
Super User
Posts: 7,060

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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?

 

 

 

Contributor
Posts: 37

Re: Generate strings using macro

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!

 

Super User
Super User
Posts: 7,060

Re: Generate strings using macro

[ Edited ]
Posted in reply to LittlesasMaster

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);
Super User
Super User
Posts: 7,060

Re: Generate strings using macro

Posted in reply to LittlesasMaster

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
☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 16 replies
  • 401 views
  • 2 likes
  • 5 in conversation