File attribute values to be converted from character to numeric - sas

Below is the code which is used to pull the file attributes to the log.
Reference code: http://support.sas.com/kb/40/934.html
%macro FileAttribs(filename);
%global rc fid fidc;
%global Bytes CreateDT ModifyDT;
%let rc=%sysfunc(filename(onefile,&filename));
%let fid=%sysfunc(fopen(&onefile));
%let Bytes=%sysfunc(finfo(&fid,File Size (bytes)));
%let CreateDT=%qsysfunc(finfo(&fid,Create Time));
%let ModifyDT=%qsysfunc(finfo(&fid,Last Modified));
%let fidc=%sysfunc(fclose(&fid));
%let rc=%sysfunc(filename(onefile));
%put NOTE: File size of &filename is &Bytes bytes;
%put NOTE- Created &CreateDT;
%put NOTE- Last modified &ModifyDT;
%mend FileAttribs;
data DSN ;
length CreateDT_ ModifyDT_ $200. ;
/*Path of the file along with the file extension*/
%FileAttribs ( C:\Derived\GRSL.log ) ;
/*Creation date of the file*/
CreateDT_ = "&CreateDT" ;
/*Modification date of the file*/
ModifyDT_ = "&ModifyDT" ;
run;
I am copying the values in the macro variables into SAS variables. The macro variables hold the 19 August 2016 09:55:09 and does not fall into the acceptable date and time formats of SAS9.2. I want to convert the CreateDT_ and ModifyDT_ to numeric. I tried doing it by manually convert search the string with SUBSTR function. Is there a way to handle it dynamically without manually searching the string for date month, year and time. Is there a way to control the file attribute formats, for example the above program returns 01 March 2017 05:22:30 o'clock during few runs and few other times the date01 MAR 2017 05:22:30. The date format keeps changing.

You can make them into DateTime constants, or use input. Here are two examples. "[datetime]"dt is a datetime constant.
One note - while it's legal to place the macro where you do, it's better to put it outside of the data step as it's a bit confusing to put it where you put it. It doesn't really run with the data step, it runs before the datastep does.
%macro FileAttribs(filename);
%global rc fid fidc;
%global Bytes CreateDT ModifyDT;
%let rc=%sysfunc(filename(onefile,&filename));
%let fid=%sysfunc(fopen(&onefile));
%let Bytes=%sysfunc(finfo(&fid,File Size (bytes)));
%let CreateDT=%qsysfunc(finfo(&fid,Create Time));
%let ModifyDT=%qsysfunc(finfo(&fid,Last Modified));
%let fidc=%sysfunc(fclose(&fid));
%let rc=%sysfunc(filename(onefile));
%put NOTE: File size of &filename is &Bytes bytes;
%put NOTE- Created &CreateDT;
%put NOTE- Last modified &ModifyDT;
%mend FileAttribs;
/*Path of the file along with the file extension*/
%FileAttribs ( c:\temp\test.txt ) ;
data DSN ;
createDT = input(symget("CreateDT"),datetime18.);
modifyDT = input(symget("modifyDT"),datetime18.);
*alternately;
createDT2 = "&createDT"dt;
put createDT datetime. createDT2 datetime.;
run;

You can use the format DATETIME18. with the input() function :
CreateDT_num=input(CreateDT_,DATETIME18.);
ModifyDT_num=input(ModifyDT_,DATETIME18.);
here in your own code
data DSN ;
format CreateDT_num ModifyDT_num DATETIME18.;
length CreateDT_ ModifyDT_ $200. ;
/*Path of the file along with the file extension*/
%FileAttribs ( C:\Derived\GRSL.log ) ;
/*Creation date of the file*/
CreateDT_ = "&CreateDT" ;
/*Modification date of the file*/
ModifyDT_ = "&ModifyDT" ;
CreateDT_num=input(CreateDT_,DATETIME18.);
ModifyDT_num=input(ModifyDT_,DATETIME18.);
run;
and if you want only the date you can then use datepart()

Related

Loop between dates

I created below macro to generate few datasets based on date macro.
%macro pull(date);
proc sql;
create table new&date as
select * from acct
where date=&date.;
quit;
%mend;
So if i want to create dataset for 20170101 20170201 20170301 20170401 20170501, all i can do is use below macro
%macro pull(20170101)
%macro pull(20170201)
%macro pull(20170301)
%macro pull(20170401)
%macro pull(20170501)
What i am planning now is create two macro variables
%let begin=20170101;
%let end =20170501;
and create datasets based on begin and end using loop. Is it possible to do that.So what i am trying to do is give start and end date as macro variable and pull records between begin and end date from acct dataset and create separate datasets for each month between start and end dates
Note dataset have monthly dates for each year.
Below is the code i am trying
%let beg="01jan2000"d;
%let end="01jan2001"d;
%macro Test;
%do date=&beg. %to &end.;
proc sql;
create table IPw_&date. as
select *
from sample
where date=&date. quit;
%end;
%mend;
%Test;
When date information must be inferred from values that are not SAS date values you will need to input the information to get a date value, and put the values iterated over to get the desired non date representation.
This example demonstrates
INPUTN function to parse the YYYYMMDD arguments into date values using informat YYMMDD8.
INTNX function to compute 1st of the month of the date values
PUTN function to convert a date value to a YYYYMMDD representation using format YYMMDDN8.
%DO %WHILE statement for iterating
INTNX function to advance the iteration variable to the start of the next month
Code
%macro pull(yyyymmdd);
%local out;
%let out = pull_&yyyymmdd;
data &out;
pull_date = input ("&yyyymmdd", yymmdd8.);
format pull_date yymmdd10.;
run;
%mend;
%macro pull_each_month(begin=, end=);
%local
begin_date end_date
begin_month end_month
pull_date pull_ymd
;
%put NOTE: &=begin &=end;
%let begin_date = %sysfunc(inputn(&begin,yymmdd8.));
%let end_date = %sysfunc(inputn(&end,yymmdd8.));
%put NOTE: &=begin_date &=end_date;
%let begin_month = %sysfunc(intnx(month,&begin_date,0));
%let end_month = %sysfunc(intnx(month,&end_date,0));
%put NOTE: &=begin_month &=end_month;
%let pull_month = &begin_month;
%do %while (&pull_month <= &end_month);
%let pull_ymd = %sysfunc(putn(&pull_month,yymmddn8.));
%put NOTE: Invoking pull for &=pull_month &=pull_ymd;
%pull (&pull_ymd)
%let pull_month = %sysfunc(INTNX(MONTH,&pull_month,1));
%end;
%mend;
%pull_each_month (
begin = 20170101
, end = 20170501
)
%macro pull_each_month(begin=, end=);
%local
begin_date end_date
begin_month end_month
pull_date pull_ymd
;
%put NOTE: &=begin &=end;
%let begin_date = %sysfunc(inputn(&begin,yymmdd8.));
%let end_date = %sysfunc(inputn(&end,yymmdd8.));
%put NOTE: &=begin_date &=end_date;
%let begin_month = %sysfunc(intnx(month,&begin_date,0));
%let end_month = %sysfunc(intnx(month,&end_date,0));
%put NOTE: &=begin_month &=end_month;
%let pull_month = &begin_month;
%do %while (&pull_month <= &end_month);
%let pull_ymd = %sysfunc(putn(&pull_month,yymmddn8.));
%put NOTE: Invoking pull for &=pull_month &=pull_ymd;
%let pull_month = %sysfunc(INTNX(MONTH,&pull_month,1));
%end;
%mend;
%pull_each_month (
begin = 20170101
, end = 20170501
)
%macro pull(begin,end);
%let i=0;
%let begin=%sysfunc(inputn(&begin,anydtdte9.));
%let end=%sysfunc(inputn(&end,anydtdte9.));
%do %until (&begin=&end);
%let begin=%sysfunc(intnx(month,&begin,&i));
%let date=%sysfunc(putn(&begin,yymmddn8.));
proc sql;
create table new&date as
select * from acct where date=&date.;
quit;
%let i=%eval(&i+1);
%end;
%mend;
%pull(20170101,20170501)

passing date variable to macro for sysfunc processing

below is my little problem to create a macro and passing in a date variable. Without using the date variable, it works with results as below.
%macro x();
%let i=-1;
%let dts = %sysfunc(today());
%put &dts; /*ok*/
%let yymm1 = %sysfunc(intnx(MONTH,&dts,&i));
%put &yymm1; /*ok*/
%let mth_beg = %sysfunc(intnx(MONTH,&dts,&i,B),date9.);
%let mth_end = %sysfunc(intnx(MONTH,&dts,&i,E),date9.);
%put &mth_beg &mth_end; /*01JAN2018 31JAN2018*/
/*** proc sql code below ** */
%mend;
%x();
log:
21231
21185
01JAN2018
31JAN2018
Now I create a macro around it and got the following error:
%macro x(dts1);
%let i=-1;
/*%let dts = %sysfunc(today());*/
%let dts = %sysfunc(&dts1);
%put &dts; /*ok*/
%let yymm1 = %sysfunc(intnx(MONTH,&dts,&i));
%put &yymm1; /*ok*/
%let mth_beg = %sysfunc(intnx(MONTH,&dts,&i,B),date9.);
%let mth_end = %sysfunc(intnx(MONTH,&dts,&i,E),date9.);
%put &mth_beg &mth_end; /*01JAN2018 31JAN2018*/
/*** proc sql code below ** */
%mend;
%x(16JAN2018);
ERROR: Function name missing in %SYSFUNC or %QSYSFUNC macro function reference.
JAN2018)
ERROR: Expected close parenthesis after macro function invocation not found.
))
ERROR: Expected close parenthesis after macro function invocation not found.
ERROR: Expected close parenthesis after macro function invocation not found.
,B),date9.) ,E),date9.)
I am not sure how to let SAS treat the date passed in as a recognized date. I know i probably used the sysfunc(&dts) wrongly or the date passed in need to adhere to certain format. i just want the date to replace today(). Can you help? I am a SAS newbie.
thanks
Wrap the date in " and end with a d. That will tell SAS to convert the string to a date:
%macro x(dts1);
%let i=-1;
/*%let dts = %sysfunc(today());*/
%let dts = "&dts1"d; /*Change here!*/
%put &dts; /*ok*/
%let yymm1 = %sysfunc(intnx(MONTH,&dts,&i));
%put &yymm1; /*ok*/
%let mth_beg = %sysfunc(intnx(MONTH,&dts,&i,B),date9.);
%let mth_end = %sysfunc(intnx(MONTH,&dts,&i,E),date9.);
%put &mth_beg &mth_end; /*01JAN2018 31JAN2018*/
/*** proc sql code below ** */
%mend;
%x(16JAN2018);
change %let dts = %sysfunc(&dts1); to
%let dts = %sysfunc(inputn(&dts1,date9. ));
SAS stores dates as the number of days since 01JAN1960. So if you do not attach a date format to the date value it will just look like an integer.
%let today=%sysfunc(today());
You can then use that integer anywhere you would use a date value.
%let next_month=%sysfunc(intnx(month,&today,1,b));
You can also represent dates by using a date literal. To make a date literal you represent the date value using something the DATE informat can read (like 16FEB2018, 16feb18, 16-FEB-2018, etc.) enclosed in quotes with the letter d appended.
%let today="%sysfunc(today(),date9)"d ;
%let date_string=13FEB2018;
%let date_value="&date_string"d ;
So date literals will work in SAS code and when you use the %sysfunc() macro function to call a SAS function (like INTNX) and they will work in the %sysevalf() macro function. But the %eval() macro function will not recognize date literals. So you will need to use %sysevalf() if you want use arithmetic or comparisons of date literals in macro logic.
%if %sysevalf(&today > '01JAN2018'd) %then ....
%let tomorrow=%sysevalf(&today +1);

Macro quoting issue in function style macro

This is a follow up question to this question.
I'm trying to simplify the way we embed images into our HTML results. The idea for this was inspired by this other question .
Basically what I am trying to do is to write a function-style macro (called %html_embed_image()) that takes an image, and converts it into a base64 format suitable for use in an HTML <img src=""> block.
Given an image such as this:
The usage would be:
data _null_;
file _webout;
put "<img src=""%html_embed_image(iFileName=hi.png)"" />";
run;
And the final output would be:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABaSURBVDhP5YxbCsAgDAS9/6XTvJTWNUSIX3ZAYXcdGxW4QW6Khw42Axne81LG0shlRvVVLyeTI2aZ2fcPyXwPdBI8B999NK/gKTaGyxaMX8gTJRkpyREFmegBTt8lFJjOey0AAAAASUVORK5CYII=" />
The question linked above shows how to do this in regular datastep code, but I am having issues getting this working in a function style macro. I posted a simplified problem I was having earlier and Tom was able to solve that simplified issue, but it doesn't seem to be working in the greater context of the function style macro.
Here is my code so far (the line causing issues is wrapped with two put statements indicating that it is the problem):
option mprint symbolgen;
%macro html_embed_image(iFileName=);
%local rc fid rc2 str str_length format_length format_mod base64_format base64_string;
/* ONLY READ IN 16K CHUNKS AS CONVERTING TO BASE64 */
/* INCREASES SIZE AND DONT WANT TO EXCEED 32K. */
%let rc = %sysfunc(filename(filrf, &iFileName, , lrecl=16000));
%let fid = %sysfunc(fopen(&filrf, i, 16000, b));
%if &fid > 0 %then %do;
%let rc = %sysfunc(fread(&fid));
%do %while(&rc eq 0);
%let rc2 = %sysfunc(fget(&fid,str,16000));
%let str = %superq(str);
/* FORMAT LENGTH NEEDS TO BE 4n/3 ROUNDED UP TO NEAREST MULTIPLE OF 4 */
%let str_length = %length(&str);
%let format_length = %sysevalf(4*(&str_length/3));
%let format_mod = %sysfunc(mod(&format_length,4));
%if &format_mod ne 0 %then %do;
%let format_length = %sysevalf(&format_length - &format_mod + 4);
%end;
%let base64_format = %sysfunc(cats($base64x,&format_length,.));
%put &=base64_format;
/* CONVERT THE BINARY DATA TO BASE64 USING THE CALCULATED FORMAT */
%put PROBLEM START;
%let base64_string = %sysfunc(putc(&str,&base64_format));
%put PROBLEM END;
%put &=base64_string;
/*&base64_string*/ /* RETURN RESULT HERE - COMMENTED OUT UNTIL WORKING */
%let rc = %sysfunc(fread(&fid));
%end;
%end;
%else %do;
%put %sysfunc(sysmsg());
%end;
%let rc=%sysfunc(fclose(&fid));
%let rc=%sysfunc(filename(filrf));
%mend;
Test the code:
%put %html_embed_image(iFileName=hi.png);
Results in:
ERROR: Expected close parenthesis after macro function invocation not found.
Any tips on how to fix this, or suggestions for workarounds would be great.
Just write the text using a data step.
%let fname=hi.png;
data _null_;
file _webout recfm=n;
if _n_=1 then put '<img src="data:image/png;base64,';
length str $60 coded $80 ;
infile "&fname" recfm=n eof=eof;
do len=1 to 60;
input ch $char1.;
substr(str,len,1)=ch;
end;
put str $base64x80.;
return;
eof:
len=len-1;
clen=4*ceil(len/3);
coded = putc(substr(str,1,len),cats('$base64x',clen,'.'));
put coded $varying80. clen ;
put '" />';
run;
If you really want to generate text in-line it might be best to add quotes so that you could call the macro in the middle of a PUT statement and not worry about hitting maximum string length.
%macro base64(file);
%local filerc fileref rc fid text len ;
%*----------------------------------------------------------------------
Assign fileref and open the file.
-----------------------------------------------------------------------;
%let fileref = _fread;
%let filerc = %sysfunc(filename(fileref,&file));
%let fid = %sysfunc(fopen(&fileref,s,60,b));
%*----------------------------------------------------------------------
Read file and dump as quoted BASE64 text.
-----------------------------------------------------------------------;
%if (&fid > 0) %then %do;
%do %while(%sysfunc(fread(&fid)) = 0);
%do %while(not %sysfunc(fget(&fid,text,60)));
%let len = %eval(4*%sysfunc(ceil(%length(%superq(text))/3)));
%if (&len) %then "%sysfunc(putc(%superq(text),$base64x&len..))" ;
%end;
%end;
%let rc = %sysfunc(fclose(&fid));
%end;
%*----------------------------------------------------------------------
Clear fileref assigned by macro,
-----------------------------------------------------------------------;
%if ^(&filerc) %then %let rc = %sysfunc(filename(fileref));
%mend base64;
So then your example data step becomes something like this:
%let fname=hi.png;
data _null_;
file _webout recfm=n;
put '<img src="data:image/png;base64,' %base64(&fname) '" />' ;
run;

Find three most recent data year for each row

I have a data set with one row for each country and 100 columns (10 variables with 10 data years each).
For each variable I am trying to make a new data set with the three most recent data years for that variable for each country (which might not be successive).
This is what I have so far, but I know its wrong because of the nest loop, and its has same value for recent1 recent2 recent3 however I haven't figured out how to create recent1 recent2 recent3 without two loops.
%macro test();
data Maternal_care_recent;
set wb;
keep country MATERNAL_CARE_2004 -- MATERNAL_CARE_2013 recent_1 recent_2 recent_3;
%let rc = 1;
%do i = 2013 %to 2004 %by -1;
%do rc = 1 %to 3 %by 1;
%if MATERNAL_CARE_&i. ne . %then %do;
recent_&rc. = MATERNAL_CARE_&i.;
%end;
%end;
%end; run; %mend; %test();
You don't need to use a macro to do this - just some arrays:
data Maternal_care_recent;
set wb;
keep country MATERNAL_CARE_2004-MATERNAL_CARE_2013 recent_1 recent_2 recent_3;
array mc {*} MATERNAL_CARE_2004-MATERNAL_CARE_2013;
array recent {*} recent1-recent3;
do i = 2013 to 2004 by -1;
do rc = 1 to 3 by 1;
if mc[i] ne . then do;
recent[rc] = mc[i];
end;
end;
run;
Maybe I don't get your request, but according to your description:
"For each variable I am trying to make a new data set with the three most recent data years for that variable for each country (which might not be successive)" I created this sample dataset with dt1 and dt2 and 2 locations.
The output will be 2 datasets (and generally the number of the variables starting with DT) named DS1 and DS2 with 3 observations for each country, the first one for the first variable, the second one for the second variable.
This is the sample dataset:
data sample_ds;
length city $10 dt1 dt2 8.;
infile datalines dlm=',';
input city $ dt1 dt2;
datalines;
MS,5,0
MS,3,9
MS,3,9
MS,2,0
MS,1,8
MS,1,7
CA,6,1
CA,6,.
CA,6,.
CA,2,8
CA,1,5
CA,0,4
;
This is the sample macro:
%macro help(ds=);
data vars(keep=dt:); set &ds; if _n_ not >0; run;
%let op = %sysfunc(open(vars));
%let nvrs = %sysfunc(attrn(&op,nvars));
%let cl = %sysfunc(close(&op));
%do idx=1 %to &nvrs.;
proc sort data=&ds(keep=city dt&idx.) out=ds&idx.(where=(dt&idx. ne .)) nodupkey; by city DESCENDING dt&idx.; run;
data ds&idx.; set ds&idx.;
retain cnt;
by city DESCENDING dt&idx.;
if first.city then cnt=0; else cnt=cnt+1;
run;
data ds&idx.(drop=cnt); set ds&idx.(where=(cnt<3)); rename dt&idx.=act&idx.; run;
%end;
%mend;
You will run this macro with:
%help(ds=sample_ds);
In the first statement of the macro I select the variables on which I want to iterate:
data vars(keep=dt:); set &ds; if _n_ not >0; run;
Work on this if you want to make this work for your code, or simply rename your variables as DT1 DT2...
Let me know if it is correct for you.
When writing macro code, always keep in mind what has to be done when. SAS processes your code stepwise.
Before your sas code is even compiled, your macro variables are resolved and your macro code is executed
Then the resulting SAS Base code is compiled
Finally the code is executed.
When you write %if MATERNAL_CARE_&i. ne . %then %do, this is macro code interpreded before compilation.
At that time MATERNAL_CARE_&i. is not a variable but a text string containing a macro variable.
The first time you run trhough your %do i = 2013 %to 2004 by -1, it is filled in as MATERNAL_CARE_2013, the second as MATERNAL_CARE_2012., etc.
Then the macro %if statement is interpreted, and as the text string MATERNAL_CARE_1 is not equal to a dot, it is evaluated to FALSE
and recent_&rc. = MATERNAL_CARE_&i. is not included in the code to pass to your compiler.
You can see that if you run your code with option mprint;
The resolution;
options mprint;
%macro test();
data Maternal_care_recent;
set wb;
keep country MATERNAL_CARE_: recent_:;
** The : acts as a wild card here **;
%do i = 2013 %to 2004 %by -1;
if MATERNAL_CARE_&i. ne . then do;
%do rc = 1 %to 3 %by 1;
recent_&rc. = MATERNAL_CARE_&i.;
%end;
end;
%end;
run;
%mend;
%test();
Now, before compilation of if MATERNAL_CARE_&i. ne . then do, only the &i. is evalueated and if MATERNAL_CARE_2013 ne . then do is passed to the compiler.
The compiler will see this as a test if the SAS variable MATERNAL_CARE_1 has value missing, and that is just what you wanted;
Remark:
It is not essential that I moved the if statement above the ``. It is just more efficient because the condition is then evaluated less often.
It is however essential that you close your %ifs and %dos with an %end and your ifs and dos with an end;
Remark:
you do not need %let rc = 1, because %do rc = 1 to 3 already initialises &rc.;
For completeness SAS is compiled stepwise:
The next PROC or data step and its macro code are only considered when the preveous one is executed.
That is why you can write macro variables from a data step or sql select into that will influence the code you compile in your next step,
somehting you can not do for instance with C++ pre compilation;
Thanks everyone. Found a hybrid solution from a few solutions posted.
data sample_ds;
infile datalines dlm=',';
input country $ maternal_2004 maternal_2005
maternal_2006 maternal_2007 maternal_2008 maternal_2009 maternal_2010 maternal_2011 maternal_2012 maternal_2013;
datalines;
MS,5,0,5,0,5,.,5,.,5,.
MW,3,9,5,0,5,0,5,.,5,0
WE,3,9,5,0,5,.,.,.,.,0
HU,2,0,5,.,5,.,5,0,5,0
MI,1,8,5,0,5,0,5,.,5,0
HJ,1,7,5,0,5,0,.,0,.,0
CJ,6,1,5,0,5,0,5,0,5,0
CN,6,1,.,5,0,5,0,5,0,5
CE,6,5,0,5,0,.,0,5,.,8
CT,2,5,0,5,0,5,0,5,0,9
CW,1,5,0,5,0,5,.,.,0,7
CH,0,5,0,5,0,.,0,.,0,5
;
%macro test(var);
data &var._recent;
set sample_ds;
keep country &var._1 &var._2 &var._3;
array mc {*} &var._2004-&var._2013;
array recent {*} &var._1-&var._25;
count=1;
do i = 10 to 1 by -1;
if mc[i] ne . then do;
recent[count] = mc[i];
count=count+1;
end;
end;
run;
%mend;

Double Looping in SAS

This problem might be trivial but I got stuck.
My problem is I've to go to each folder for a dataset and transpose the data.
I wrote the following code and it works fine.
OPTIONS MPRINT MLOGIC SYMBOLGEN;
%LET LOC=E:\folder;
%macro test1(k,l);
libname libary "&loc.\&k\&l.";
data dataset_&l.;
set libary.dataset_original;
run;
proc transpose data=dataset_&l. out=dataset_&l._T;
run;
%mend;
%test1(var_1,var'_1);
%test1(var_2,var'_2);
%test1(var_3,var'_3);
The issue with this code is it's not dynamic in terms of folder structure. E.g. if there's another 4 extra folders, I've to write "%test1(var_3,var'_3);"4 times.
So I tried writing the following code to make it more dynamic. But unfortunately it's not working. Can anybody please tell me where I'm making the mistake.
OPTIONS MPRINT MLOGIC SYMBOLGEN;
%LET LOC=E:\folder;
%let k=var_1 var_2 var_3;
%let l=var'_1 var'_2 var'_3;
%macro words(string);
%local count word;
%let count=1;
/* The third argument of the %QSCAN function specifies the delimiter */
%let word=%qscan(&string,&count,%str( ));
%do %while(&word ne);
%let count=%eval(&count+1);
%let word=%qscan(&string,&count,%str( ));
%end;
%eval(&count-1)
%mend words;
%macro test1(k,l);
libname libary "&loc.\&k\&l.";
data dataset_&l.;
set libary.dataset_original;
run;
proc transpose data=dataset_&l. out=dataset_&l._T;
run;
%mend;
%macro test();
%do i=1 %to %words(&k.);
%do j=1 %to %words(&l.);
%let var=%scan(&k.,&i.,str());
%let var1=%scan(&l.,&j.,str());
%test1(&var.,&var1.);
%end;
%end;
%mend;
%test();
Thanks!
Try this:
/* Set your base directory */
%let base = E:\Folder;
/* Pipe output from dir */
filename flist pipe "dir /s /b /a:-h &base";
/* Read files from pipe */
data files;
length file dir $ 200 name $ 50 ext $ 10;
infile flist;
input #1 file $ &;
/* File extension */
ext = scan(file, -1, ".");
/* File name */
name = scan(scan(file, -1, "\"), 1, ".");
/* Directory */
rfile = reverse(file);
dir = reverse(substr(rfile, index(rfile, "\") + 1));
/* Select only SAS datasets */
if upcase(ext) = "SAS7BDAT" then output;
drop rfile;
run;
/* Define a macro to process each file */
%macro trans_file(dir, name);
libname d "&dir";
proc transpose data = d.&name out = d.&name._t;
run;
libname d clear;
%mend trans_file;
/* Run on all files */
data _null_;
set files;
call execute(cats('%trans_file(', dir, ",", name, ");"));
run;
This gets the file list by submitting the Windows command dir. It gets all files in the specified directory and its subdirectories.
This approach then uses a simple macro that defines a data library, reads a dataset from the library, writes a transposed dataset to it, then clears it. The macro is called for each file in the list using call execute.