SAS Macro pulling monthly data - sas

Hello I am trying to build a macro process that allows me to pull data from the most current month to a x amount of months(historically), however it seems to only pull for one month any thoughts ?
%LET START_DATE = 20140731;
DATA _NULL_;
START_DATE = input(cat(&START_DATE),YYMMN6.);
FORMAT START_DATE date9.;
MON_START_DT=put(START_DATE,date9.);
CALL SYMPUTX('MON_START_DT',put(MON_START_DT,9.));
RUN;
%MACRO DO_FOR(NUM_OF_MONTHS);
%DO I = 0 %TO &NUM_OF_MONTHS-1;
DATA _NULL_;
END_DATE=intnx('month',"&MON_START_DT"d,&I,'end');
FORMAT END_DATE yymmdd10.;
MON_END_DATE=put(END_DATE,yymmdd10.);
MON_END_DATE=COMPRESS(MON_END_DATE," (-)");
FORMAT MON_END_DATE $8.;
CALL SYMPUTX('BATCH_ID',put(MON_END_DATE,$8.));
RUN;
PROC SQL;
sysecho;
CREATE TABLE work.table AS
SELECT FROM WHERE
/*ex This table contains months of data*/
%END;
%MEND DO_FOR;
%DO_FOR(NUM_OF_MONTHS=03);

Shouldn't &I have a minus sign in front of it to go backwards in time rather than forwards in time? If you start at the current month and only go forwards you will only get one month.
END_DATE=intnx('month',"&MON_START_DT"d,-&I,'end');

Related

SAS MACRO to Cycle Month End Dates

I have a set of code that I am manually adjusting month end dates. The query which runs and uses the dates has left joins to pull data for each declared date. I've been looking at macros because this is labor intensive to change all the dates by one month all the way until the most recent completed month. There's got to be a way to loop through and change each declared month end date by one month and do a loop to run the query until it gets to the most recent completed month end date.
So after the below runs entirely, it would up each declared date by one month and show the month end date. Each data set that runs would be be BEDT. So the first run would be jan2018, so on and so forth.
Can someone assist or point me into the right direction? I've read through so much documentation and have gotten no where. Thanks in advance.
%Let BEdt='01JAN2018'd
%let dt1='28FEB2018'
%let dt2='31MAR2018'
%let dt3='30APR2018'
%let dt4='31MAY2018'
%let dt5='30JUN2018'
%let dt6='31JUL2018'
%let dt7='31AUG2018'
%let dt8='30SEP2018'
%let dt9='31OCT2018'
%let dt10='30NOV2018'
%let dt12='31DEC2018'
%let dt12='31JAN2019'
Let's use something that has a start date and a number of months to pull. We'll use intnx() to increment each month one by one until we reach the last month. intnx() will also help us calculate the start and end dates.
%macro get_data(start=, months=12);
/* Convert start/end values into SAS dates */
%let start_dt = %sysfunc(inputn(&start., date9.));
%do i = 0 %to &months.;
/* Calculate the start and end months for the month of data in the loop */
%let month_s = %sysfunc(intnx(month, &start_dt., &i., B) );
%let month_e = %sysfunc(intnx(month, &start_dt., &i., E) );
%put Pulling data for %cmpres(%sysfunc(putn(&month_s., date9.)) - %sysfunc(putn(&month_e., date9.)));
/***********************************/
/***** SQL/DATA Step goes here *****/
/***********************************/
%end;
%mend;
%get_data(start=01JAN2018);
In the area where you'd add SQL or DATA step code, it could look like this:
data want_&month_s.;
set have;
where date BETWEEN &month_s. AND &month_e.;
run;
Output:
Pulling data for 01JAN2018 - 31JAN2018
Pulling data for 01FEB2018 - 28FEB2018
Pulling data for 01MAR2018 - 31MAR2018
Pulling data for 01APR2018 - 30APR2018
Pulling data for 01MAY2018 - 31MAY2018
Pulling data for 01JUN2018 - 30JUN2018
Pulling data for 01JUL2018 - 31JUL2018
Pulling data for 01AUG2018 - 31AUG2018
Pulling data for 01SEP2018 - 30SEP2018
Pulling data for 01OCT2018 - 31OCT2018
Pulling data for 01NOV2018 - 30NOV2018
Pulling data for 01DEC2018 - 31DEC2018
Pulling data for 01JAN2019 - 31JAN2019
Depending on the complexity of the statement you want to run for each month, you can also use call execute instead of a macro loop.
data _null_;
start_date = "&start."d;
do i = 0 to &months.;
month_start = intnx("month", start_date, i, "B");
month_end = intnx("month", start_date, i, "E");
call execute(
'data want_'||strip(i)||';'||
'set have;'||
'where date between '||month_start||' and '||month_end||';'||
'run;'
);
end;
run;
You only have to be careful about when macro variables get resolved. I nice article on this can be found here
* Do whatever you would do for one month in a macro;
%macro do_a_month(begin_d, end_d);
data want_&begin_d;
set have;
where data between "&begin_d"d and "&end_d"d;
run;
%mend;
* call the macro as much as needed;
data _null_;
begin_d = '01JAN2018'd;
do while (begin_d le '31JAN2019'd);
end_d = intnx("month", begin_d, 0, "E");
call execute ( '&do_a_month('
|| put(begin_d, date9.) ||','
|| put(end_d, date9.) ||')';
* go to next month;
begin_d = end_d + 1;
end;
run;

SAS Macro to create multiple data sets

Good afternoon,
I am decent with SAS but I've never written macros.
I have a DB where I need to break out in separate datasets ID's where the date in a field occurs. E.g. All ID's with a date in Jan 2018 would be one dataset, All ID's with a date in Feb 2018 would be another data set, so on and so forth. Field name is ZDate.
I found this which seems to do exactly what I want. However I think my date isn't in the correct format. The date I'm pulling is in a timestamp in snowflake and I'm converting it to a date with to_date. It's showing as formatted date (16FEB2020) in the original vintagedata data set but the subsequent data sets are completely blank.
%macro month;
%local mindate maxdate i date month ;
proc sql noprint;
select min(ZDate),max(ZDate)
into :mindate , :maxdate
from vintagedata
;
quit;
data
%do i=0 %to %sysfunc(intck(month,&mindate,&maxdate));
%let date=%sysfunc(intnx(month,&mindate,&i));
%let month=%sysfunc(putn(&date,monyy7.));
&month
%end;
;
set vintagedata;
%do i=0 %to %sysfunc(intck(month,&mindate,&maxdate));
%let date=%sysfunc(intnx(month,&mindate,&i));
%let month=%sysfunc(putn(&date,monyy7.));
if intnx('month',date,0)=&date then output &month ;
%end;
run;
%mend;
%month;

Is there anyway to change dates dynamically and write them into a table in SAS?

I'm working on a code that gets tables dynamically and associates them with calculated dates for further calculations.
I have trouble calculating these dates because their values won't change if i change the only parameter I start with.
PS : I opted to do them inside data null step so I can use them for other queries.
%let dtDMRT= 1FEB2016;
/*calculated dates */
DATA _null_;
DAY_DMRT_DEB = intnx('year',"&dtDMRT"d,-1);
format DAY_DMRT_DEB DATE9.;
call symputx('DAY_DMRT_DEB',DAY_DMRT_DEB);
DAY_DMRT_FIN = '&dtDMRT'd;
format DAY_DMRT_FIN DATE9.;
call symputx('DAY_DMRT_FIN',DAY_DMRT_FIN);
DATE_DMRT_1Y = intnx('year',"&dtDMRT"d,1);
format DATE_DMRT_1Y DATE9.;
call symputx('DATE_DMRT_1Y',DATE_DMRT_1Y);
run;
PROC SQL THREADS ;
CREATE TABLE DATAMART_SEG AS
SELECT *,
&DAY_DMRT_DEB as DAY_DMRT_DEB format= DATE9.,
&DAY_DMRT_FIN as DAY_DMRT_FIN format= DATE9.,
&DATE_DMRT_1Y As DATE_DMRT_1Y format= DATE9.
FROM DMRT.MYDATAMART_&dtDMRT
RUN;
The first test with %let dtDMRT= 1JAN2016; I get the right results in WORK.DATAMART_SEG :
DAY_DMRT_DEB = '01JAN2015'd
DAY_DMRT_FIN = '01JAN2016'd
DATE_DMRT_1Y = '01JAN2017'd
How ever with %let dtDMRT= 1FEB2016; I get :
DAY_DMRT_DEB = '01JAN2015'd
DAY_DMRT_FIN = '01FEB2016'd
DATE_DMRT_1Y = '01JAN2017'd
I know I can do this directly into the table with either PROC SQL or DATA step but I need those macro variables for other purposes
According to the documentation for intnx the default for alignment is set to BEGINNING. So what you observing is absolutely correct. Set the alingment to SAME and intnx will do what you want.
DATA _null_;
DAY_DMRT_DEB = intnx('year',"&dtDMRT"d,-1,'SAME');
format DAY_DMRT_DEB DATE9.;
call symputx('DAY_DMRT_DEB',DAY_DMRT_DEB);
DAY_DMRT_FIN = "&dtDMRT"d;
format DAY_DMRT_FIN DATE9.;
call symputx('DAY_DMRT_FIN',DAY_DMRT_FIN);
DATE_DMRT_1Y = intnx('year',"&dtDMRT"d,1,'SAME');
format DATE_DMRT_1Y DATE9.;
call symputx('DATE_DMRT_1Y',DATE_DMRT_1Y);
run;

How can I use different sets of date values depending on the date

I am looking to automate a daily report for my company but I have run in to a bit of trouble. The report gets updated only on the 2nd working day of each month. I found some code on the SAS website which works out what the 2nd working day of any month is.
data scdwrk;
/* advance date to the first day of the month using the INTNX function */
second=intnx('month',today(),0);
/* determine the day of the week using the WEEKDAY function */
day=weekday(second);
/* if day=Monday then advance by 1 */
if day=2 then second+1;
/* if day=Sunday then advance by 2 */
else if day=1 then second+2;
format second date9.;
run ;
I have also set a flag that compares todays date to the date from this generated by this piece of code.
I now need to find a way that if the code is run on the first working day of the month then it runs a particular set of macro date variables
%let start_date="&prevmnth;
%let end_date= &endprevmnth;
%let month= &prevyearmnth;
and then when its run on the 2nd working day of the month it uses the other set of macro date variables (calender month)
%let start_date="&currmnth;
%let end_date= &endcurrmnth;
%let month= &curryearmnth;
Any help on this would be greatly appreciated.
I have some recent code that does just this. Here is how I tackled it.
First, create a table of holidays. This can be maintained yearly.
Second, create a table with the first 5 days of the month that are not weekend days.
Third, delete holidays.
Finally, get the second value in the data set.
data holidays;
format holiday_date date9.;
informat holiday_date date9.;
input holiday_date;
datalines;
01JAN2015
19JAn2015
16FEB2015
03APR2015
25MAY2015
03JUL2015
07SEP2015
26NOV2015
25DEC2015
;
data _dates;
firstday = intnx('month',today(),0);
format firstday date date9.;
do date=firstday to firstday+5;
if 1 < weekday(date) < 7 then
output;
end;
run;
proc sql noprint;
delete from _dates
where date in (select holiday_date from holidays);
quit;
data _null_;
set _dates(firstobs=2);
call symput("secondWorkDay",put(date,date9.));
stop;
run;
%put &secondWorkDay;

SAS MACRO FROM PROC SQL DATE ERROR

Hello I am trying to put an specific date from a dataset into a macro so i can use it in a DATA step , but i always get 01-JAN-1960 insteed of the date that i want
my code is the next one:
proc sql noprint ;
select WEEK_START
into :WEEK_START
from date_table
WHERE FW= 5;
quit;
%let start=&WEEK_START;
%LET TODAY= TODAY();
I made this so i can see the date that i want:
DATA TEMP;
DATE =&TODAY;
DATE1= &start;
FORMAT DATE DATE1 datE11.;
RUN;
And the result is:
DATE : 06-OCT-2014
DATE1 : 01-JAN-1960
proc sql noprint ;
select today()-1 as WEEK_START
into :WEEK_START
from maps.africa;
quit;
%let start=&WEEK_START;
%LET TODAY= TODAY();
DATA TEMP;
DATE =&TODAY;
DATE1= &start;
FORMAT DATE DATE1 datE11.;
RUN;
When I run this, both populate correctly.
Additionally, the value of Date1 in your example is the date value for the numeric value of 0. It looks like your original data is being populated incorrectly.