I have a table like TABLE_NAME_&DATE. The &DATE. parameter is dynamic and each month should be shown like MMYYYY (previous month and couurent year). e.g TABLE_NAME_JAN2022
This parameter will be created in User Written Code inside a job.
My query is what code should I put to make this table dynamic and recived monthly table with data paramter for previous month
Thank you
You can use the DATE() , also known as TODAY(), function to get the current date. You can use the INTNX() function to find the previous month. You can use the MONYY7. format to generate a string in MONYYYY style. You can use CALL SYMPUTX() function to store the string into a macro variable.
data _null_;
call symputx('date',put(intnx('month',date(),-1),monyy7.));
run;
If you want to do it with only macro code you will need to wrap the DATE() and INTNX() function calls inside of %SYSFUNC() macro function calls.
%let date=%sysfunc(intnx(month,%sysfunc(date()),-1),monyy7.);
Related
In SAS, the min/max function can take only one input argument. E.g.
min(42)
My question is why would people want to use these functions with only one input argument? What is it compared to (when there is only one input)?
You might be using a variable list whose size is not known in advance. So it is useful if the function handles lists of only one value. For example if you want to MIN() of all variables with names that start with COST you could code:
min_cost = min(of cost:);
Or you might be generating the list of values via macro logic or other code generation techniques.
proc sql noprint; select cost into :costs separated by ',' from have; quit;
data want;
min_cost = min(&costs);
run;
Note it still requires at least one argument, but you can code around that by providing it an extra missing value.
min_cost=min(., of cost:);
And finally if they are using PROC SQL then they are actually calling a different function. The SQL aggregate function. That function only allows one argument but it aggregates the value over multiple observations.
proc sql ;
create table want as
select product, min(cost) as min_cost
from have
group by product
;
quit;
So I will briefly explain my code structure before I dive into the issue.
I've a macro
%Sales (Outdata= , dt =, Outdata2= , Outdata3= );
(
I create a table &outdata by (Select * from XYZ);
Proc SQL;
Create table &Outdata._1 as
(
)
%mend Sales
Now I call the macro
%Sales (Outdata = sales_final_Oct17, dt='2017-10-01');
Libname ABCDEFG
I Create a data set
Data ABCDEFG.all_sales_test;
Set ABCDEFG. all_Sales
sales_final_Oct17_1;
incur_month = month(rept_dt);
run;
Above (1 to 3) is the original code flow and it works fine.
My Problem:
I'm using a dynamic way of generating file name for each month (so that each month I do not manually enter file_name_month and date.
File name code
%let Last_Month = intnx('month', current_date,-1, "beginning");
Name = 'Sales_final';
Last_Month_Name = name|| put(&last_month, monyy7.);
Call SYMPUTX('Last_Month_Name_v', Last_Month_Name);
run;
Call Macro
%Sales(outdata=&Last_Month_Name, dt = 'Dynamic date');
Till this point everything works fine. The moment I create a data set similar to step 3 (above), the code breaks.
Libname ABCDEFG
Data ABCDEFG.all_sales_test;
Set ABCDEFG.all_Sales
Last_Month_Name_1;
incur_month = month(rept_dt);
run;
> Error Message: File ABCDEFG.LAST_MONTH_NAME_1.DATA does not exist.
What should I do to get rid of this error? It seems, if I pass a static name in the macro and then use the same name with "_1" it works fine but when I pass dynamic reference, then the data Set step fails with the above error message.
Any help is much appreciated. I'm new to SAS so excuse me if it's a silly question. Thanks.
In (1) the macro code is using the value of the macro parameter (or local macro variable) OUTDATA to create a dataset. In (2) you are supplying a value for OUTDATA in your call and in (3) you are using the same value again in the set statement.
One way to not have to type the value twice is to store the value into a macro variable then just reference that macro variable's value in steps (2) and (3).
So in (4) you did create a macro variable,Last_Month_Name_v , but you then used the value of a different macro variable, &Last_Month_Name in the macro call. But instead of using the macro variable in the set statement you just referenced some other dataset,Last_Month_Name_1 , that you never mentioned before at all.
Here are the simplified key steps in the process you want for how to create and use the macro variable. I have put in ... to show where I have left out parts of a statement or statements so we can concentrate on the flow of the macro variable and its value.
First you set the macro variable to some name that you want to use. Let's just use anything as the name for this example.
%let last_month_name= anything;
Then you use the value in the macro call to create the dataset. Notice the & before the name, that is what tells the macro processor to replace the name with the value. The period after the name tells the macro processor that is the end of the macro variable name.
%sales(outdata=&last_month_name. .... )
Then you can use the value again later when you want to tell the set statement which dataset to read.
set .... &last_month_name. ;
Now your posted macro %sales does not actually create the dataset named anything. Instead it appears to create a dataset named anything_1. Personally I don't know why that is there, but if you keep it that way then you need add the _1 back to the end of the macro variable's value in the set statement. Just do it in the same way that you did in the macro's code.
set .... &last_month_name._1 ;
Working with macros is one of the harder parts of SAS and can be very confusing to newcomers. Below is a simplified working example that demonstrates the approach I would take.
First we dynamically calculate the name of the table we want to save the results to:
%let current_date = %sysfunc(date());
%let last_month = Sales_final_%sysfunc(intnx(month, ¤t_date, -1, beginning), monyy7.);
%put &=last_month;
The output from the put statement in the above step is:
LAST_MONTH=Sales_final_OCT2017
Note that in the above code, I'm passing two parameters to %sysfunc(). The first parameter is the call to the intnx() function. The second parameter (monyy7.) is what format to apply to the result being returned from the function call.
Also note that there is no need to concatenate the prefix (Sales_final_) to the %sysfunc() result because when working with the macro language, the result of %sysfunc() is subsituted in place. There is no concatenation operator in the macro language at all - everything is based off of macro substitution.
Then it's a simple case of passing that value into the macro as shown below:
%macro sales(outdata=);
proc sql;
create table &outdata._1 as select * from sashelp.class;
quit;
%mend;
%sales(outdata=&last_month);
You should be able to modify the above into what you need.
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";
I am struggling with this compress function in the code below that I am trying to convert.
Old code: (This code works and returns the results below)
data _null_;
%let startdt='2015/11/1';
date_num=compress(&startdt,"'");
call symputx('date_num',date_num);
%put &startdt;
%put &date_num;
run;
This code returns values for the macro variable startdt as 2015/11/1 and datenum as 2015/11/1.
I am trying to achieve similar functionality using macro variables for dates.
New code: (This code gives me an error and I am not able to figure out why)
data _null_;
dt = date();
last_mth_beg = intnx('month',dt,-1,'beginning');
call symput('startdt',put(last_mth_beg,YYMMDDS10.));
date_num=compress(&startdt,"'");
call symputx('date_num',date_num);
%put &startdt;
%put &date_num;
run;
I am getting an error when I run this new code. I would like to get results as in the old code.
Please help. Thank you!
Your first data step is just removing the quotes from your macro variable. You can do this in macro code by either using %sysfunc() to call the compress() function. Or even just use the %scan() function.
%let date_num = %scan(&startdt,1,%str(%'));
In the second one it looks like you are trying to use INTNX() function on the date value. But your macro variables do not contain date values. If you want to treat '2015/11/1' as if it was a date then you will need to use an input function to convert it first.
%let last_mth_beg = %sysfunc(intnx(month,%sysfunc(inputn(&date_num,yymmdd10)),-1,b),yymmdd10);
I am not sure why your old code is not giving you an error. The first time you run it, you should see the error,
WARNING: Apparent symbolic reference DATE_NUM not resolved.
Then, after the data step has run, &DATE_NUM will have a value. You cannot use %PUT inside a data step to display a macro variable you are creating within the data step.
In your second set of code, the value of the STARTDT macro variable you are creating does not have single quotes around it in the first place. If you just run the following, you will get the correct result:
data _null_;
dt = date();
last_mth_beg = intnx('month',dt,-1,'beginning');
call symput('startdt',put(last_mth_beg,YYMMDDS10.));
run;
%put &startdt;
When I run it, I see
2016/11/01
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.