I would like to be able to save a file in SAS with today's date. I'm having trouble creating the file path with today's date.
Given that today's current date is 3/27/2018. I would like the created file path to be this:
"/sasFolder/MyFileName(3-27-2018).xlsx"
My current code is:
data _null_;
call symput('dateMonth', month(date()));
call symput('dateDay', day(date()));
call symput('dateYear', year(date()));
run;
%let filePath = "/sasFolder/MyFileName(&dateMonth.-&dateDay.-&dateYear.).xlsx";
data _null_;
put &filePath;
run;
Currently my output is this, with _ representing spaces.
"/sasFolder/MyFileName(___________3-__________26-________2018).xlsx"
I would like for the filename to not have all theses extra spaces in the name. Any ideas on how to do this?
You can do this very easily without a data step using %sysfunc() - this lets you call a SAS function and apply a format at the same time, eg:
%let filePath = "/sasFolder/MyFileName(%sysfunc(today(), mmddyyd10.)).xlsx";
%put &=filepath;
Which gives:
FILEPATH="/sasFolder/MyFileName(03-27-2018).xlsx"
There is a format for that date style already. Looks like you using the MMDDYYD10. format. You could use it in your data step code.
data _null_;
call symputx('datestamp', put(date(),mmddyyd10.));
run;
%let filePath="/sasFolder/MyFileName(&datestamp).xlsx";
Or skip the data step and use the %sysfunc() macro function to call the date() function and apply the format.
%let datestamp=%sysfunc(date(),mmddyyd10.);
You can even eliminate the extra macro variable.
%let filePath="/sasFolder/MyFileName(%sysfunc(date(),mmddyyd10.)).xlsx";
Note that I recommend that you switch to using YYMMDD format instead of MMDDYY format. First it will prevent your English friends from confusing December tenth and October twelfth. Second it will allow your file names to sort in chronological order.
Figured it out. Needed to change symput to symputx to remove the spaces.
The code is:
data _null_;
call symputx('dateMonth', month(date()));
call symputx('dateDay', day(date()));
call symputx('dateYear', year(date()));
run;
%let filePath = "/sasFolder/MyFileName(&dateMonth.-&dateDay.-&dateYear.).xlsx";
data _null_;
put &filePath;
run;
Related
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_×tamp._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));
I have been working on this for 3 days now and have tried all I can think of including %str(),%bquote(), translate() and tranwrd() to replace single apostrophe with double apostrophe or %’
The below data step and macro work fine until I hit a last name which contains an apostrophe e.g. O’Brien. I then encounter syntax errors due to un closed left parentheses. The below code I have left what I thought was closest to working with the tranwrd included.
Any assistance you can provide is greatly appreciated.
%macro put_data (object1,id);
Proc http
method=“put”
url=“https://myurl/submissionid/&id”
in=&object1;
Headers “content-type”=“application/json”;
Run;
%mend;
data _null_;
Set work.emp_lis;
call execute(catt(‘%put_data(‘,’%quote(‘’{“data”:{“employeeName”:”’,tranwrd(employeeName,”’’”,”’”),’”}}’’),’,id,’)’));
run;
Craig
There are a wide potential of problems in constructing or passing a json string in SAS macro. Proc JSON will produce valid json (in a file) from data and that file in turn can be specified as the input to be consumed by your web service.
Example:
data have;
length id 8 name $25;
input id& name&;
datalines;
1 Homer Simpson
2 Ned Flanders
3 Shaun O'Connor
4 Tom&Bob
5 'X Æ A-12'
6 Goofy "McDuck"
;
%macro put_data (data,id);
filename jsonfile temp;
proc json out=jsonfile;
export &data.(where=(id=&id));
write values "data";
write open object;
write values "name" name;
write close;
run;
proc http
method="put"
url="https://myurl/submissionid/&id"
in=jsonfile
;
headers "content-type"="application/json";
run;
%mend;
data _null_;
set have;
call execute(cats('%nrstr(%put_data(have,',id,'))'));
run;
I was able to find issue with my code with the tranwrd statement was backwards and it needed to be moved to the proc sql create table statement. I also needed to wrap &object1 in %bquote. This was the final code that worked.
When creating table wrap variables in tranwrd as below.
tranwrd(employeeName, “‘“,”’’”)
% macro put_data (object1,id);
Proc http
method=“put”
url=“https://myurl/submissionid/&id”
in=%bquote(&object1);
Headers “content-type”=“application/json”;
Run;
%mend;
data _null_;
Set work.emp_lis;
call execute(catt(‘%put_data(‘,’%quote(‘’{“data”:{“employeeName”:”’,employeeName,’”}}’’),’,id,’)’));
run;
Just use actual quotes and you won't have to worry about macro quoting at all.
So if your macro looks like this:
%macro put_data(object1,id);
proc http method="put"
url="https://myurl/submissionid/&id"
in=&object1
;
headers "content-type"="application/json";
run;
%mend;
Then the value of OBJECT1 would usually be a quoted string literal or a fileref. (There are actually other forms.) Looks like you are trying to generate a quoted string. So just use the QUOTE() function.
So if your data looks like:
data emp_lis;
input id employeeName $50.;
cards;
1234 O'Brien
4567 Smith
;
Then you can use a data step like this to generate one macro call for each observation.
data _null_;
set emp_lis;
call execute(cats
('%nrstr(%put_data)('
,quote(cats('{"data":{"employeeName":',quote(trim(employeeName)),'}}'))
,',',id
,')'
));
run;
And your SAS log will look something like:
NOTE: CALL EXECUTE generated line.
1 + %put_data("{""data"":{""employeeName"":""O'Brien""}}",1234)
NOTE: PROCEDURE HTTP used (Total process time):
real time 2.46 seconds
cpu time 0.04 seconds
2 + %put_data("{""data"":{""employeeName"":""Smith""}}",4567)
NOTE: PROCEDURE HTTP used (Total process time):
real time 2.46 seconds
cpu time 0.04 seconds
I would like to set a dataset by using a reference to dataset name however Iam getting error message: ERROR: File dataset_name123 does not exist(work.dataset123 does exist) What is wrong?
data _null_;
%let product = 'dataset_name123';
set work.&product nobs = row_no;
put row_no;
put &product;
run;
Member names are not quoted. Remove the quotes from your macro variable. In macro code everything is character so there is no need to add quotes around string literals. The quotes become part of the value of the macro variable.
%let product = dataset_name123;
%put &=product;
data _null_;
set work.&product nobs = row_no;
put row_no;
put "&product";
stop;
run;
If you do include quotes in a dataset reference then SAS will interpret it as the physical name of the dataset file itself. So code like:
data want;
set 'dataset_name123';
run;
would look for a filename 'dataset_name123.sas7bdat' in the current working directory.
It is not a great idea to do a %let statement in a data step. Macrovariables and SAS variables are created differently.
There are two problems in this code. First one is quotes around macrovariable, which after resolution will be used for table name and hence your query fails as table names cannot be in quotes .
second one is put statement for macro variable for macro variable to resolve you need %put.
below is modified code.
data class;
set sashelp.class;
run;
data _null_;
%let product = class;
set work.&product nobs = row_no;
put row_no;
%put &product;
run;
I have a SAS script that reads in a CSV file and stores it in a SAS data set:
LIBNAME IN '\\path\Data';
FILENAME CSV '\\path\Data\DT.csv';
DATA IN.DT;
INFILE CSV DLM=',' DSD FIRSTOBS=1;
INPUT KEY VALUE1 VALUE2;
RUN;
I want to change it such that instead of expecting the input to be named DT.csv, it would accept an input named DT-2016-03-03-TEST.csv, or whatever the current date is. In other words, I need to use a dynamic value in my FILENAME statement.
Here is what I have so far:
%LET curday = %SYSFUNC(day("&sysdate"d));
%LET curmonth = %SYSFUNC(month("&sysdate"d));
%LET curyear = %SYSFUNC(year("&sysdate"d));
%PUT %SYSFUNC(PUTN(&curday, z2.));
FILENAME CSV "\\path\Data\DT-&curyear-&curmonth-&curday-TEST.csv";
But the string it generates is like Data\DT-2016-3-3-TEST.csv rather than Data\DT-2016-03-03-TEST.csv
In other words, the trailing zeros are not there. What am I doing incorrectly?
You'll need to use either a macro variable or a big group of macro functions (whichever you'd like). We'll go with creating macro variables for readability purposes. Based upon what you've said, we know a few things about the pattern:
It starts with DT-
It has today's date in a yyyy-mm-dd format
It ends in .csv
Two of these are static values, and one needs to be dynamic in a specific format. Let's get crackin'.
Start off by storing the path in its own macro variable. This makes the code more generalizable to other applications (i.e. you can copy/paste old code for new programs! It's good to be lazy in the programming world).
%let path = \\path\data;
Next, let's build our dynamic pattern using a %let statement. We know it starts with DT-:
___________________________________________
%let file = DT-
___________________________________________
We can now cross #1 off the list! Let's knock out #2.
Two functions will help us get this in the order that we want:
%sysfunc()
today()
We'll encapsulate today() with %sysfunc(). %sysfunc() lets us run most non-macro-language SAS functions, and also has the added benefit of returning the value in a format that you desire using an additional argument. This is really helpful for us here.
So, let's grab today's date as a numeric SAS date, then convert it to yymmddx10 format, where x is some delimiter keyword. We'll use yymmddd10. - that is, a format that specifies yyyy-mm-dd. The extra d means dash.
___________________________________________
%let file = DT-%sysfunc(today(), yymmddd10.)
___________________________________________
2 is now out of the way. Hard part's over! All we need to do is append .csv to it, and we'll be all set.
___________________________________________
%let file = DT-%sysfunc(today(), yymmddd10.).csv;
___________________________________________
You can confirm the macro variable file's value with a %put statement:
%put NOTE: This is my filename: &file;
You should see in green text in the log NOTE: This is my filename: DT-2016-03-03.csv
Now, we'll just put it all together:
%let path = \\path\data;
%let file = DT-%sysfunc(today(), yymmddd10.).csv;
libname IN "&path";
filename CSV "&path\&file";
data in.DT;
infile csv dlm=',' dsd firstobs=1;
input key value1 value2;
run;
You've now got a dynamic way to read in these CSVs, and you can adapt this code elsewhere. Awesomesauce. I think you've earned yourself a celebratory coffee, and maybe a biscotti or two; don't go too crazy.
Stu's answer is absolutely correct. For the tl;dr version.
%put echos stuff to the log. All you are doing is "putting" the result of %SYSFUNC(PUTN(&curday, z2.)) to the log. You are not updating the value in &curday.
Try
%LET curday = %SYSFUNC(PUTN(&curday, z2.));
Do that for the other curmonth, too.
Take the time and read Stu's answer.
I am submitting the following SAS code:
proc format;
picture mysdt
low-high = '%Y%0m%0d%0H%0M' (datatype =datetime);
run;
DATA _NULL_;
call symput("Today", Put(datetime(),mysdt.));
run;
%put t_&today;
The resulting log shows 2 spaces before the datetime:
t_ 201504240150
The problem here is when my macro is resolved it is creating leading space. Why is it creating spaces?
My output should be:
t_201504240150
I know the solution but just wanted to know the reason.
DATA _NULL_;
call symput("Today", strip(Put(datetime(),mysdt.)));
run;
The reason for this is that your format is set up with a default length of 14. Therefore, when you go to put your value into &today it is stored with leading blanks to fill out the length to 14. From the SAS documentation:
DEFAULT=length
specifies the default length of the picture. The value for DEFAULT= becomes the length of picture if you do not give a specific length when you associate the format with a variable.
So, there are a number of options:
Set the default format length to match the expected length of your datetime value (using DEFAULT=12):
proc format;
picture mysdt (default=12)
low-high = '%Y%0m%0d%0H%0M' (datatype =datetime);
run;
Specify the width in your format:
DATA _NULL_;
call symput("Today", strip(Put(datetime(),mysdt12.)));
run;
Or, as previously answered, use call symputx to trim whitespace:
DATA _NULL_;
call symputx("Today", strip(Put(datetime(),mysdt.)));
run;
Personally, I'd fix the format to default to 12, then you won't need to remember to specify width or use call symputx each time.
call symputx remove leading and tailing space.
DATA _NULL_;
call symputx("Today", Put(datetime(),mysdt.));
run;