SAS, Make a macro variable contains YYYYMM - sas

I have a SAS statement.
%let data = SampleData_200001_201603;
The data name is changing every time I run the code. For example:
run in 201604 then name= SampleData_200001_201603;
run in 201605 then name= SampleData_200001_201604;
run in 201606 then name= SampleData_200001_201605;
How can I write %let data = ; to make it automatic? Thanks.

If you are using the current date then you can use the YYMMN6. format to get the date in that format.
%let data = SampleData_200001_%sysfunc(date(),yymmn6);
If you need the previous month then use INTNX() function.
%let data = SampleData_200001_%sysfunc(intnx(month,%sysfunc(date()),-1),yymmn6);

%let date = 201603;
%let data = SampleData_200001_&date.;
and loop through a list of dates

I had enough of multiple %sysfunc's to get what I wanted. I wrote a macro routine that allows assignation of dates to macro variables using the format we want. No twists and turns with %sysfunc.
The code is here. And it lets you do that: assign to a macro variable named "thisMonth" the value of today(), with format YYMMn6. :
%letdate(thisMonth, today(), fmt=YYMMn6.)
log says:
*** Variable macro thisMonth = 201604 ***
And then
%let myFile = someName_&thisMonth;
%put &myFile;
log says:
someName_201604
The macro is documented in French but it should be self-explanatory for the most part.
EDIT:
Note that you can use any function normally reserved to data steps as the second parameter:
%letdate(firstDayLastMonth, intnx("MONTH", today(), -1, "BEGIN"), date9.)
log says:
*** Variable macro firstDayLastMonth = 01MAR2016 ***

Related

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));

How to set report dates automatically for %str arguments

I'm compiling order data using a program that has already been built, but am trying to update a section of the code to take today's date minus 61 days and plus 56 days for the respective start and end dates, rather than a manually typed in date as shown below. The current, functional code as well as one of my attempts is below.
The current format that is working and executing is:
/* Set report dates (dd-mm-yyyy) */
%let fore_start = %str(08-SEP-2019);
%let fore_end = %str(03-JAN-2020);
I'm attempting to build something like:
/* Set report dates (dd-mm-yyyy) */
%let fore_start = %str(TODAY()-61);
%let fore_end = %str(TODAY()+56);
I'm looking for help devising a syntactically sound line to solve this problem. Any help would be appreciated!
Try this:
%let fore_start = %sysfunc(putn(%eval(%sysfunc( today() ) - 61), ddmmyyd10.) );
%let fore_end = %sysfunc(putn(%eval(%sysfunc( today() ) + 56), ddmmyyd10.) );
It looks like there's a lot there, but it really isn't. Removing all of the syntax of macro language and converting it into data step functions, here's all you are doing:
fore_start = put(today() - 61, ddmmyyd10.);
fore_end = put(today() + 56, ddmmyyd10.);
There are a few things at play:
In macro language, SAS functions such as putn and today() need to both be enclosed with %sysfunc(). %sysfunc() is your connection to SAS system functions and the macro facility.
%eval will subtract two integers from each other.
putn, another SAS function, will convert the resulting SAS date into your desired format of ddmmyyd10.. putn is required for macro language instead of put.
The date representations you show as being kept in macro variables fore_start and fore_end are actually dd-mmm-yyyy, or format DATE11.
The %sysfunc marco function will invoke a DATA step function and optionally format the result. The INTNX function will perform date arithmetic.
%let fore_start = %sysfunc(intnx(DAY, %sysfunc(today()), -61), DATE11);
%let fore_end = %sysfunc(intnx(DAY, %sysfunc(today()), +56), DATE11);

SAS: How to proc import with different date?

I have 10 csv files that would like to do PROC IMPORT, one at each time, depending on the value user input. For example, user will input 201801 to run January 2018 csv file(PROC IMPORT).
For that case, i tried to use substring &period(which stores the yymmn6. value which user input) and then from there, put in proc import. My code as below:
%let period=201812;
%macro convertdate();
data convertdate;
year=substr("&period",1,4);
month=substr("&period",5,2);
if month='01' then newmonth='jan';
if month='02' then newmonth='feb';
if month='03' then newmonth='mac';
if month='04' then newmonth='apr';
if month='05' then newmonth='may';
if month='06' then newmonth='jun';
if month='07' then newmonth='jul';
if month='08' then newmonth='aug';
if month='09' then newmonth='sep';
if month='10' then newmonth='oct';
if month='11' then newmonth='nov';
if month='12' then newmonth='dec';
run;
/*Assign convertdate the only distinct record into macro, then set as the data step for proc import*/
%if month='01' %then %do;
%let newmonth=jan;
%end;
/*proc import and remaining transformation from existing script*/
proc import out=rmr_raw_source
file="/sasdata/source/user_files/re_&newmonth.2018.xlsx"
dbms=xlsx replace;
sheet="re_&newmonth.2018";
getnames=no;
dbsaslabel=none;
run;
%mend;
%convertdate;
However, it wont work. I am getting warning below:
WARNING: Apparent symbolic reference NEWMONTH not resolved.
Does anyone have better solution to it?
You can try something as follows:
%let period = '201801'; /*7*/
%global month;
data test123;
period = . /*1*/
full_date = cats(period,'01'); /*2*/
format converted_date DATE10.; /*3*/
converted_date = input(full_date, yymmdd8.); /*4*/
month = put(converted_date,monname3.); /*5*/
call symput('month',month); /*6*/
run;
Create a SAS variable out of Macro.
Set to first date of the given month.
Create a new var and set the date format.
convert the TEXT date to SAS date.
get the month name out of date created above.
create a macro variable named 'month' out of SAS variable month.
Make macro variable 'month' global.
You can now use month macro variable anywhere in the code.

Get values of Macro Variables in a SAS Table

I have a set of input macro variables in SAS. They are dynamic and generated based on the user selection in a sas stored process.
For example:There are 10 input values 1 to 10.
The name of the macro variable is VAR_. If a user selects 2,5,7 then 4 macro variables are created.
&VAR_0=3;
&VAR_=2;
&VAR_1=5;
&VAR_2=7;
The first one with suffix 0 provides the count. The next 3 provides the values.
Note:If a user select only one value then only one macro variable is created. For example If a user selects 9 then &var_=9; will be created. There will not be any count macro variable.
I am trying to create a sas table using these variables.
It should be like this
OBS VAR
-----------
1 2
2 5
3 7
-----------
This is what I tried. Not sure if this is the right way to do approach it.
It doesn't give me a final solution but I can atleast get the name of the macro variables in a table. How can I get their values ?
data tbl1;
do I=1 to &var_0;
VAR=CAT('&VAR_',I-1);
OUTPUT;
END;
RUN;
PROC SQL;
CREATE TABLE TBL2 AS
SELECT I,
CASE WHEN VAR= '&VAR_0' THEN '&VAR_' ELSE VAR END AS VAR
from TBL1;
QUIT;
Thank You for your help.
Jay
SAS helpfully stores them in a table for you already, you just need to parse out the ones you want. The table is called SASHELP.VMACRO or DICTIONARY.MACROS
Here's an example:
%let var=1;
%let var2=3;
%let var4=5;
proc sql;
create table want as
select * from sashelp.vmacro
where name like 'VAR%';
quit;
proc print data=want;
run;
I think the real issue is the inconsistent behavior of the stored process. It only creates the 0 and 1 variable when there are multiple selections. I think that your example is a little off. If the value of VAR_0 is three then their should be a VAR_3 macro variable. Also the value of VAR_ and VAR_1 should be set to the same thing.
To fix this in the past I have done something like this. First let's assign the parameter name a macro variable so that the code is reusable for other programs.
%let name=VAR_;
Then first make sure the minimal macro variables exist.
%global &name &name.0 &name.1 ;
Then make sure that you have a count by setting the 0 variable to 1 when it is empty.
%let &name.0 = %scan(&&&name.0 1,1);
Then make sure that you have a 1 variable. Since it should have the same value as the macro variable without a suffix just re-assign it.
%let &name.1 = &&&name ;
Now your data step is easier.
data want ;
length var $32 value $200 ;
do i=1 to &&&name.0 ;
var=cats(symget('name'),i);
value=symget(var);
output;
end;
run;
I don't understand your numbering scheme and recommend changing it, if you can; the &var_ variable is very confusing.
Anyway, the easiest way to do this is SYMGET. That returns a value from the macro symbol table which you can specify at runtime.
%let VAR_0=3;
%let VAR_=2;
%let VAR_1=5;
%let VAR_2=7;
data want;
do obs = 1 to &var_0.;
var = input(symget(cats('VAR_',ifc(obs=1,'',put(obs-1,2.)))),2.);
output;
end;
run;

SAS Export date format

Hi I am trying to import data (successfully) from a folder that is a date so the file path reads /year/month/date (*today's date)
I am then tweaking some of the data (again successfully). Once that is done I want to export it to a folder that is 29 days forward from the folder I took it from.
Here is my current macro:
%LET TODAY = %SYSFUNC(TODAY());
%PUT &TODAY;
%LET TODAYA = %SYSFUNC(PUTN(&TODAY,DDMMYYn8.));
%PUT &TODAYA;
%LET TWENTYNINE = %SYSFUNC(PUTN(&TODAY.+29,DDMMYYn8.));
%PUT &TWENTYNINE;
%LET T_DATE = %SYSFUNC(PUTN(&TODAY,DDMMYYn8..));
%LET T_YEAR = %SYSFUNC(YEAR(&TODAY));
%LET T_MONTH = %SYSFUNC(MONTH(&TODAY));
%LET P_DATE = %SYSFUNC(PUTN(&TWENTYNINE,DDMMYYn8..));
**%PUT &P_DATE;
%LET P_YEAR = %SYSFUNC(YEAR(&P_DATE));
%LET P_MONTH = %SYSFUNC(MONTH(&P_DATE));**
The P_Date reveals the error:
ERROR: Argument 1 to function MONTH referenced by the %SYSFUNC or %QSYSFUNC macro function is not
a number.
ERROR: Invalid arguments detected in %SYSCALL, %SYSFUNC, or %QSYSFUNC argument list. Execution
of %SYSCALL statement or %SYSFUNC or %QSYSFUNC function reference is terminated.
But I cant get my head around it any help would be massively appreciated.
Imbricating %sysfunc's is handy:
%LET P_YEAR = %SYSFUNC(YEAR(%SYSFUNC(TODAY())+29));
%LET P_MONTH = %SYSFUNC(MONTH(%SYSFUNC(TODAY())+29));
%PUT &P_YEAR &P_MONTH;
Results in:
2016 2
EDIT
(Try solving it by yourself first, but here's a full solution...)
data _null_;
target = today() + 29;
format target YYMMDDS10.;
put target=;
call symput("target", put(target, YYMMDDS10.));
run;
%put ⌖
2016/02/24
If you want to determine the source path to use for today's date then use the TODAY() function. You can apply the YYMMDDS format to have it displayed as YYYY/MM/DD.
%let frompath=%sysfunc(today(),yymmdds10);
If you want to calculate the target path from the source path then you can use the INPUTN() function to convert it back to a date, add 29 and use PUTN() function to convert it back to a string.
%let topath=%sysfunc(putn(29+%sysfunc(inputn(&frompath,yymmdd10)),yymmdds10));