Can you include macro in SAS proc import filename? - sas

I need to import the same excel file into SAS every week, and filenames have different dates like below:
file_01012021.xls
file_01072021.xls
When I set up macro variables I'm getting an error due to the " ' " in the MMDDYYYY macro variable
%let MMDDYYY = '01012021'; /*Update each week*/
%let extension '.xls';
%let file = 'File_'
%let filename = &file||put(&MMDDYYYY,8.)||&extension;
proc import
out = dataset1
datafile = "/workspace/&filename"
dbms = xls replace;
run;
Are there ways to get this to work?

You do not need quotes in a macro variable assignment statement, and you do not need to concatenate them with a data step concatenation statement. Simply put them together by resolving each macro variable.
%let mmddyy = 01012021;
%let extension = .xls;
%let file = File_;
%let filename = &file.&mmddyy.&extension;

Related

Macro only stores part of the string

I create my variable like this:
data Concat_var;
Table_periode_MDR = CAT("\\Afdeling\HS-OKO\Oko\Likviditet\Likviditetsstyring\LCR\Indberetning\2022\",&Periode,"\RLI\Output_Daglig_LCR\MDR_korrektion.csv");
Table_periode_Dagligkorr = CAT("\Afdeling\HS-OKO\Oko\Likviditet\Likviditetsstyring\LCR\Indberetning\2022\",&Periode,"\RLI\Månedlig_LCR_RLI\WORK_QUERY_FOR_DAGLIGEKORREKTIONER.csv");
Table_periode_weights_m = CAT("\Afdeling\HS-OKO\Oko\Likviditet\Likviditetsstyring\LCR\Indberetning\2022\",&Periode,"\RLI\Månedlig_LCR_RLI\Weights_M.csv");
Table_periode_weights_d = CAT("\Afdeling\HS-OKO\Oko\Likviditet\Likviditetsstyring\LCR\Indberetning\2022\",&Periode,"\RLI\Output_Daglig_LCR\Weights_D.csv");
Table_periode_W_D_LCR = CAT("\Afdeling\HS-OKO\Oko\Likviditet\Likviditetsstyring\LCR\Indberetning\2022\",&Periode,"\RLI\Output_Daglig_LCR\W_D_LCR.csv");
Table_periode_W_M_LCR = CAT("\Afdeling\HS-OKO\Oko\Likviditet\Likviditetsstyring\LCR\Indberetning\2022\",&Periode,"\RLI\Månedlig_LCR_RLI\W_M_LCR.csv");
run;
PROC SQL NOPRINT;
SELECT DISTINCT
Table_periode_MDR,
Table_periode_Dagligkorr,
Table_periode_weights_m,
Table_periode_weights_d,
Table_periode_W_D_LCR,
Table_periode_W_M_LCR
INTO :Table_periode_MDR,
:Table_periode_Dagligkorr,
:Table_periode_weights_m,
:Table_periode_weights_d,
:Table_periode_W_D_LCR,
:Table_periode_W_M_LCR
FROM Concat_var;
When looking in the "Concat_var" everything looks right.
The issue is that when I use the string to import files like this:
proc import datafile=&Table_periode_MDR
out=MDR_korrektion
replace
dbms=csv
replace;
getnames=yes;
delimiter=';';
run;
But I get an error because the string is only:
\Afdeling\HS-OKO\Oko\Likviditet\Likviditetsstyring\LCR\Indberetning\2022\202208\RLI\Output_Daglig_LCR\MDR_ko
How can I get the whole string when I create my variable?
I hope you can point me in the right direction.
cat() automatically sets the variable length to 200, and your text is within that range so that does not appear to be the issue.
Although I cannot directly recreate your results, consider creating your macro variables directly. You do not need to use a separate data step with a SQL :into to concatenate them. The macro processor automatically knows where macro variables start and end with & and .
%let folder = \\Afdeling\HS-OKO\Oko\Likviditet\Likviditetsstyring\LCR\Indberetning\2022\;
%let Table_periode_MDR = &folder.\&periode.\RLI\Output_Daglig_LCR\MDR_korrektion.csv;
%let Table_periode_Dagligkorr = &folder.\&periode.\RLI\Månedlig_LCR_RLI\WORK_QUERY_FOR_DAGLIGEKORREKTIONER.csv;
%let Table_periode_weights_m = &folder.\&periode.\RLI\Månedlig_LCR_RLI\Weights_M.csv;
%let Table_periode_weights_d = &folder.\&periode.\RLI\Månedlig_LCR_RLI\Weights_M.csv;
%let Table_periode_W_D_LCR = &folder.\&periode.\RLI\Output_Daglig_LCR\W_D_LCR.csv;
%let Table_periode_W_M_LCR = &folder.\&periode.\RLI\Månedlig_LCR_RLI\W_M_LCR.csv;

SAS - Macro Variable in Proc Export file name

I'm trying to transfer code that pulls a survey sample every month into a cronjob, but the last step I'm having an issue with in automating the code is with the file name in the proc export step.
I have the following macro variables defined at the beginning of the code:
%let today = date();
%let month = month(today);
%let year = year(today);
After I pull the data from our database and filter appropriately, I have a code that outputs the files as a pipe delimited .txt file. This file format is important to preserve:
proc export data=mkt.project_&timestamp._group
outfile="/filepath/project_&year.&month._group" dbms=dlm Replace;
delimiter='|';
run;
The file output name doesn't recognize the macro variables, however, so instead of getting the year and month, it just names them as "project_&year.&month._group".
Can anybody help with this?
Thanks!
Macro variables contain text.
You have set yours to text strings that look like SAS function calls. But then you did not use the strings to generate SAS code where such a function call would make sense. Instead you put the function call into the name of a file.
440 %let today = date();
441 %let month = month(today);
442 %let year = year(today);
443 %put "/filepath/project_&year.&month._group";
"/filepath/project_year(today)month(today)_group"
One way to execute SAS functions in macro code is to use the macro function %sysfunc(). If you want to generate the 6 digit string in they style YYYYMM you can use the YYMMN6. format. So you could generate your filename like this:
"/filepath/project_%sysfunc(date(),yymmn6.)_group"
Or your other macro variables like this:
%let today = %sysfunc(date());
%let month = %sysfunc(month(&today),z2.);
%let year = %sysfunc(year(&today));

Reading n files into SAS to create n datasets

I have just started learning SAS, and I'm using the following code to read xlsx files:
proc import out = data_lib.dataset_1
datafile = 'C:\data_folder\data_file_1.xlsx'
dbms = xlsx replace;
sheet = 'Sheet1';
getnames = yes;
run;
This has been working fine for me, but I'd like to supply the code with a list of filenames to read and a list of dataset names to create, so that the code need only appear once. I have looked at several instructional web pages about using macros, but I've been unable to translate that information into working code. Any help would be greatly appreciated. I'm using SAS 9.4, 64 bit.
I'd offer a modified version of kl78's suggestion, avoiding macros. Again, assuming you have the file names in a SAS data set, use a data step to read the list of file names and use call execute to run your proc import code for each file name.
data _null_;
set t_list;
call execute (
"proc import out = " || datasetname || "
datafile = '"|| filename ||"'
dbms = xlsx replace;
sheet = 'Sheet1';
getnames = yes;
run;");
run;
So, suppose you have your filenames and datanames in a table called t_list with variablename datasetname and filename, you could try something like this:
%macro readexcels;
data _null_;
set t_list (nobs=nobs);
call symputx(cat("libname_",_n_), datasetname);
call symputx(cat("filename_",_n_), filename);
if _n_=1 then
call symputx("nobs", nobs);
run;
%do i=1 %to &nobs;
proc import out = &&libname_&i;
datafile = "&&filename_&i"
dbms = xlsx replace;
sheet = 'Sheet1';
getnames = yes;
run;
%end;
%mend;
%readexcels;
In the datastep you read every entry of your table with datasetname and listname and create macrovariables with a numeric suffix. You only need to create a macrovariable for the number of entries once, so i did it when n = 1, you could also do this at eof.
Then you have a do loop, and with every loop you read the specific excel and write it in the specific dataset.
You need to write it like &&libname&i, because at first this resolves to &libname_1, and after this resolves to the variablevalue...

SAS libref not recognized in macro loop

I've run into an odd SAS quirk that I can't figure out - hopefully you can help.
I have a simple macro loop that imports CSV files and for some reason if I use a libref statement in the "out=" part of the import procedure, SAS doesn't recognize the libref as a valid name. But if I use the same libref in a data step, it works just fine.
The specific error it gives is: "ERROR: "TESTDB." is not a valid name."
I'd like to figure this out because I work with pretty big files and want to avoid reading through them more times than is necessary.
Here's the code that works, with some comments in it. I got around the issue by reading in the files, then writing them to permanent SAS datasets in a second step, but ideally I'd like to import the files directly into the "TESTDB" library. Any idea how to get SAS to recognize a libref in the "out=" statement of the import procedure?
libname testdb "C:\SAS test";
%let filepath = C:\SAS test\;
%macro loop(values);
%let count=%sysfunc(countw(&values));
%do i = 1 %to &count;
%let value = %qscan(&values,&i,%str(,));
proc import datafile = "&filepath.&value..csv"
out = &value dbms=csv replace; getnames=yes;
/*"out=testdb.&value" in the line above does not work*/
run;
data testdb.&value; set &value; run;
/*here the libref testdb works fine*/
%end;
%mend;
%loop(%str(test_a,test_b,test_c));
Thanks in advance for your help!
john
Perhaps try:
out=testdb.%unquote(&value)
Sometimes the macro language does not unquote values automatically. With result that the extra quoting characters introduced by a quoting function (%qscan %str %bquote %superq etc) cause problems.
Strange error. I am not able to pin it. My guess is that it has something to do with how the value macro variables are being created. When I moved the value variable creation to a data step and used Call Symputx, it works.
%macro loop(files);
/* Create macro variables for files.*/
data _null_;
count = countw("&files.",",");
call symputx("count",count,"L");
do i = 1 to count;
call symputx(cats("file",i),scan("&files.",i,","),"L");
end;
run;
/* Read and save each CSV as a sas table. */
%do i=1 %to &count.;
proc import datafile = "&filepath.&&file&i...csv"
out = testdb.&&file&i. dbms=csv replace; getnames=yes;
run;
%end;
%mend;
%loop(%str(test_a,test_b));

Calling a macro variable from libname

How do I call a macro variable in the from clause of proc sql if I wish to use it in a libname?
Let me show you what I mean:
options nofmterr;
libname FRST "/ecm/retail/mortgage/nbk6kra/LGD/data/frst_201312bkts";
libname HELN "/ecm/retail/mortgage/nbk6kra/LGD/data/heln_201312bkts";
libname HELC "/ecm/retail/mortgage/nbk6kra/LGD/data/helc_201312bkts";
%let pathLGD = /new/mortgage/2014Q4/LGD;
%let prod = FRST;
/**************** Segment calculation **************** Date filter to be consistent with model documentation for segmented tables****************/
%macro Performance(prod);
proc sql;
create table lgd_seg_&prod as
select distinct
SegDT_LGD_2013,
min(ScoreDT_LGD_2013) as min_range,
max(ScoreDT_LGD_2013) as max_range,
count(*) as count,
mean(lgd_ncl_adjusted) as LGD_actual,
mean(ScorePIT_LGD_2013) as LGD_pred_pit_1,
mean(ScoreDT_LGD_2013) as LGD_pred_dt_1
from "&prod."scored;
where coh_asof_yyyymm > 200612
group by 1;
quit;
PROC EXPORT DATA=lgd_seg_&prod._fs
OUTFILE= "&pathLGD./lgd_seg.xlsx"
DBMS=XLSX REPLACE;
SHEET="&prod._lgd_seg_fs";
RUN;
%mend;
%Performance(prod=FRST);
%Performance(prod=HELN);
%Performance(prod=HELC);
So in the "from" clause, the macro is supposed to read FRST.scored, HELN.scored, and HELC.scored respectively. Currently it cannot find the file, and if I were to remove the quotation marks, then it'd become "work.FRSTscored".
I hope I've made this clear. Any input and comment is appreciated.
When you want to follow the the resolved value of a macro variable with an immediate additional character you should escape the macro variable with a full stop (.). For example:
%let start = one;
%put &start.two;
%put &start..two;
%put &startend;
onetwo
one.two
WARNING: Apparent symbolic reference STARTEND not resolved.
So your code should read from &prod..scored;.
If you ever need to you can also delay the resolution of a macro variable with double ampersand (&&):
%let end = two;
%let onetwo = three;
%put &&one&end;
%put &&&start&end;
Three
Three
Or:
%let three = inception;
%put &&&&&&&start&end;
inception
Remove quotation marks applied outside the macro variable prod and use two dots after macro variable (one to signify end of macro variable name and second one to specify the table name after the libname reference.
from &prod..scored