SAS - Need to make the filepath used in an INFILE statement dynamic - sas

I have a SAS procedures that runs every morning and it takes in a raw data file for the day called "Filename_20141117.txt". The last part of the file name is changing everyday to the date for that day.
I want to make the INFILE statement in my SAS script smarter so that it knows to get the current day's file. I was trying to do a date concatenation, something like this:
infile cat('G:\Finance\RawData\Filename_',year(today()),month(today()),day(today()),'.txt')
Also, is there a way to declare variables and work with them in SAS, and not have them created as a table in your output? I'm a C/C#/VB programmer learning to program in SAS.
I was thinking that i could make 3 string variables - day, month, and year. Populate each variable with the corresponding value using the Day(), Month() and Year() function, with Today() as the date input. Then i was going to take these 3 variables and concatenate them to get my '20141118' that would be located at the end of the .txt file.
However it doesn't like me doing this. If anyone knows how to do this that would be fantastic. I'm very new to SAS Programming and its concepts.
Thanks in advance.

The most basic version of your statement would be:
INFILE "G:\Finance\RawData\Filename_%sysfunc(today(),yymmddn8.).txt";
To explain fully:
%sysfunc is a macro function in SAS which allows you to use data-step functions in open code, it takes one (optionally two) arguments:
The first argument of %sysfunc is the data-step function in question, in this case we want the value of TODAY(), so that is used.
The second argument (optional) provides the SAS format in which the result should be returned. The SAS format of choice for the date representation you need is yymmddn8. (literally year_year_month_month_day_day, the n represents 'no-separators', and 8 is the length). (e.g. 20141118)
If we were to omit the second argument, we'd get the number of days since 01JAN1960.
If I were to run the statement today it would look like this:
INFILE "G:\Finance\RawData\Filename_20141118.txt";
Also, use of double-quotes here is required because we are using a macro function. If we used single quotes, it would look for a file with the unresolved value of the string above and would most likely fail.
To check what it would resolve to, simply add %PUT to the front of the line, and then just run that line in isolation. The log will show what is returned.

Related

what's the difference on dealing char between where statement and if statement in SAS 9.4M6

Recently, I happen to find an interesting thing:
data test;
set sashelp.class;
if _N_ in (2 3 5 7) then name = '';
run;
data test;
set ;
where name;
run;
The result is: data Test has 15 observations.
I use SAS 9.4M6 for over a year and don't remember that where statment can deal with char type variable just like boolean type variable. I strightly change where to if and it leads the results: name is not a numeric variable and data Test has 0 observation.
So here is my two questions:
1. Is where name; another way of where name is not missing? if not, what happens when submitwhere name?
2. When did this kind of code(where <variable>;) start be allowed in SAS?
Thanks for any tips.
Yes it is a test for non empty values. I have used it for years, mainly when interactively browsing a dataset. I suspect it has been there since SAS introduced the WHERE statement, or at least since they re-factored it to use the same syntax as SQL WHERE clauses.
WHERE statements use PROC SQL style syntax (use of LIKE no use of variable lists) but IF statements use normal SAS syntax.
So if you used
if name ;
in your data step then you would see notes about SAS trying to convert the character variable NAME into a number that it can evaluate as FALSE (zero of missing) or TRUE (any other value). Since the names in SASHELP.CLASS cannot be converted to numbers then all of them will be treated as FALSE.
Interesting find! I also have not noticed this. I tried this on both 9.4M4 and 9.4M5 and received the same results. This may be something added even earlier than that. I see no documentation on it as well. From testing, here is what I am able to see:
where statements can automatically convert characters such as as if name to boolean statements
if statements do not automatically convert characters to boolean and require the user to explicitly state the character you are trying to exclude, e.g.
Code:
data want;
set test ;
if(NOT missing(name));
run;
I cannot tell when this was added, but it is earlier than versions I have access to. Your test code would be a great quiz question!

proc sql doing a insert into within a call execute in SAS

Within a data setp I am using a "call execute" like the one below:
Everything works fine except the last 2 variables mhstdtc2 and mhendtc2, these variables are num type with an informat and format of date9.
I receive a note that numeric variables are being converted to character on that line, How should the dates be inserted on the call execute statment. Thanks
I have tried removing the quotes which creates a messy call execute
call execute("proc sql;
insert into leaddata values("||subjid||","||mhterm||","||mhstdtc_dtr||","||mhstdtc_dtr||","||mhstdtc_dtr||","||sitemnemonic||","||mhstdtc2||"d,"||mhendtc2||"d);quit;");
Before generating code make sure you know what code you want to generate. Looks like you are trying to generate something like this:
values(101,Stomach Pain,30NOV2018,15DEC2018,Clinic 47);
But you need to generate quotes around your character variables. Also there is no need to convert your dates into human readable date literals, just leave them as the raw number of days.
call execute(catx(' ','proc sql;','insert into leaddata','values('
,catx(',',quote(subjid),quote(mhterm),date1,number2,....)
,');quit;'));
But if you have the data in a dataset why not just insert directly from the data set?
insert into leaddata select subjid,mhterm,.... from have ;

Call sas program in a loop

I have a SAS program . I need to call the SAS program multiple times, each time passing a different date parameter.
Am I correct that first I need to wrap the entire .sas file into some kind of macro and then I need to call that macro repeatedly? Or is there a way to do it without wrapping it in a macro ?
In short: maybe, yes.
Maybe:
If you have specific program you wish to launch each time with certain parameter that can be done from command line. There is sysparm-variable, which is imported to the program, like following:
> <path>SASHome\SASFoundation\9.4\sas.exe -sysparm "21537"
which in SAS code is equivalent to:
%let sysparm = 21537;
This enables you to restrict, label data wit your input as much need be. Also you can run your program as many times with any parameter you wish. What we do is parse the Sysparm to allow multiple parameter to be passed.
For more on Sysparm, see documentation
Yes:
If you want to run your code mulitple times in a session you ideally want something like:
%macro do_stuff(your_date):
%put Processing date &your_date.;
data data_&your_date.;
set someLib.begin;
if your_date < data_date < (your_date-20) ;
run;
/*And so forth....*/
%mend do_stuff;
%do_stuff(date_1);
%do_stuff(date_2);
%do_stuff(date_3);

Include macro in a file name

In SAS I like to make a dynamic filename since I am browsing my data on a daily tabel.
I have tried to include a macro in the filename like this:
%let date=input(put(today()-3,ddmmyy6.),6.); *This is equal to todays date-3 (format = 190317)
filename nlp "DailyB.DG%date";
It does not work can you help me?
To get a intuition of what I like to do I have posted a example below
I want to have a date minus 3 days from today in this format:DDMMYY (190317)
So if i run the code the day after it would be 200317.
The variable should then be put into the code so I get the following:
filename nlp 'DailyB.DG190317';
If you want a macro variable to resolve a function, you need %sysfunc. Here's one way to do that.
%let date=%sysfunc(putn(%eval(%sysfunc(today())-3),ddmmyyn6.)); *This is equal to todays date-3 (format = 190317);
%put &=date;
The first %sysfunc asks for the result of today(), the second asks for the result to be formatted. %eval is needed to subtract 3 from the value, as #Quentin points out in comments.
Alternately, call symputx would work here if you're more comfortable in the data step.
data _null_;
call symputx('date',put(today()-3,ddmmyyn6.));
run;
%put &=date;
So what you currently tried is going to end up with a filename statement like
filename nlp "DailyB.DGinput(put(today()-3,ddmmyy6.),6.)";
To run functions in macro code you need to use %SYSFUNC(). You will also need to use the PUTN() function since the PUT() function doesn't work with %SYSFUNC().
%let date=%sysfunc(putn(%sysfunc(today())-3,ddmmyyn6));
filename nlp "DailyB.DG&date";
If you can get the process changed I would recommend using 8 characters for the date part of the name so that you can include the century. Also if you use Year,Month,Day order for your date string your generated filenames will sort in proper date order and also prevent users confusing Columbus Day for Dewey Decimal System Day.
You need to use the %sysfunc() and %eval() macro functions to evaluate the Data Step functions outside the Data Step. As Joe says:
%let date=%sysfunc(putn(%eval(%sysfunc(today())-3),ddmmyyn6.));
Then you need to change your % to a &
filename nlp "DailyB.DG&date";

blocking the values after a specific date

I've got the following question.
I'm trying to run a partial least square forecast on a data model I have. Issue is that I need to block certain line in order to have the forecast for a specific time.
What I want would be the following. For June, every line before May 2014 will be blocked (see the screenshot below).
For May , every line before April 2014 will be blocked (see the screenshot below).
I was thinking of using a delete through a proc sql to do so but this solution seems to be very brutal and I wish to keep my table intact.
Question : Is there a way to block the line for a specific date with needing a deletion?
Many thanks for any insight you can give me as I've never done that before and don't know if there is a way to do that (I did not find anything on the net).
Edit : The aim of the blocking will be to use the missing values and to run the forecast on this missing month namely here in June 2014 and in May 2014 for the second example
I'm not sure what proc you are planning to use, but you should be able to do something like the below.
It builds a control data set, based on a distinct set of dates, including a filter value and building a text data set name. This data set is then called from a data null step.
Call execute is a ridiculously powerful function for this sort of looping behaviour that requires you to build strings that it will than pass as if they were code. Note that column names in the control set are "outside" the string and concatenated with it using ||. The alternative is probably using quite a lot of macro.
proc sql;
create table control_dates as
select distinct
nuov_date,
put(nuov_date,mon3.)||'_results' as out_name
from [csv_import];
quit;
data _null_;
set control_dates;
call execute(
'data '||out_name||';
set control_dates
(where=(nuov_date<'||nouv_date||'));
run;');
call execute('proc [analysis proc] data='||out_name||';run;');
run;