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;
Related
I have a table where I compare the results week to week.
I have aggregations of old dates using these functions.
%let date_old=%sysfunc(intnx(year,%sysfunc(Today()),-1,s));
%put &=date_old;
proc format;
value vintf low-&date_old = 'OLD' other=[yymmd7.];
run;
/*agregujemy wyniki do daty vintf jako old*/
proc summary data=tablea_new nway;
class policy_vintage;
format policy_vintage vintf.;
var AKTYWNE WYGASLE;
output out=newtabe sum=;
And I would like to do exactly the same, only to aggregate the dates to show the yearly range, i.e. 2021-01-2022-01. Or the current year 2021-01-2021-12. Is the following sample okay? What's the best way to do this?
%let date_future=%sysfunc(intnx(year,%sysfunc(Today()),+12,s));
%put &=date_future;
proc format;
value vintfutr +&date_future= 'FUTURE' other=[yymmd7.];
run;
%let date_old=%sysfunc(intnx(year,%sysfunc(Today()),-1,s));
%let date_future=%sysfunc(intnx(year,%sysfunc(Today()),+1,s));
proc format;
value vintf
low-&date_old = 'OLD'
&date_future-high = 'FUTURE'
other=[yymmd7.]
;
run;
I am building code that imports a daily file of sales from last 30 days, then replaces last 30 days of records in a main table. I want to only replace the last 30 days if the imported daily file has enough records:
proc sql;
select min(sale_date) into :oldestSale from daily_sales;
quit;
Here's a logic that I want to build in SAS:
IF oldestSale < (today() - 30) THEN
PROC SQL to replace
ELSE
do nothing
END
What would be the best solution? This is trivial in Python which I'm translating this from, but I'm stuck on SAS syntax for doing anything similar...
The 'logic' is quite vague in specifics, but the gist seems to be
import daily sales
presume daily sales is complete and every daily sale is represented
if daily sales info starting date is more than 30 days ago
remove all sales from main table from starting date
append current daily sales
One approach would be to have a macro that peforms the conditional remove/append as a 'replace' action.
%macro process_daily_sales;
proc import … out=daily_sales;
run;
%local oldestSale;
%let oldestSale = %sysfunc(today()); %* sentinel value just in case;
proc sql;
select min(sale_date) into :oldestSale from daily_sales;
quit;
%local gap;
%let gap = %eval ( %sysfunc(today()) - &oldestSale );
%if &gap > 30 %then %do;
proc sql;
delete from main_sales where sales_date >= &oldestSale;
quit;
proc append base=main_sales data=daily_sales;
run;
%end;
%mend;
I have a table with observations from the date 01.08.2016 to 30.08.2016.
How to create 12 tables in the following way:
the first one contains observations from the date 01.08.2016 to 20.08.2016;
the second one contains observations from the date 01.08.2016 to 21.08.2016;
...
the 12th one contains observations from the date 01.08.2016 to 30.08.2016.
I think that it is better to do using loops, but dont know how.
This assumes that the date is in SAS date format. You can use character comparison if your date is in character format.
The data vector still contains the observation after the output statement is executed. So as long as the condition is true, the data step will write the same observation to multiple datasets. Also, I think you will need the date comparisons till 31st August if you want 12 datasets.
data want1 want2 want3 ... want12;
set have;
if date <= '20AUG2016'd then output want1;
if date <= '21AUG2016'd then output want2;
if date <= '22AUG2016'd then output want3;
.
.
.
if date <= '31AUG2016'd then output want12;
run;
It is probably better to use WHERE statements than to make separate tables. But to do either without hardcoding you need to use code generation. That is normally done using macro logic.
%macro split(start,stop);
%local i n;
%let n=%sysfunc(intck(day,&start,&stop));
%let n=%eval(&n+1);
DATA
%do i=1 %to &n;
WANT&i
%end;
;
set have ;
%do i=1 %to &n ;
if date <= %sysfunc(intnx(day,&start,&i-1)) then output WANT&i ;
%end;
run;
%mend split;
%split('20AUG2016'd,'31AUG2016'd);
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.
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');