BookmarkSubscribeRSS Feed
dkcoop
Fluorite | Level 6

I have a macro that creates 15 datasets by date from one dataset that contains 15 months of data indexed by datekey in the format yyyymmdd.  It is a simple set statement with a where clause. Because I'm rewriting this code from someone else, there are already 15 individual datasets in mylib.  I only want 12 rolling months of datasets.  In the code I've attached, I created all 15 datasets again because I thought that would be easiest.  What I'd really like going forward is to read 12 months of data from the large dataset (which I can by adjusting _N_) and delete the earliest mylib dataset that's already out there.

 

/*date_key is in format yyyymmdd.*/
proc sql;
create table testdata as
select distinct date_key from mylib.mth_datasets;
quit;
/*the most recent date will be id 1*/
proc sort data=testdata out=unique nodupkey;
	by descending date_key:
run;
data unique;
	set unique;
	id=_N_;
data _null_;
	set unique end=last;
	if last then call symput('N', put(id, 3.));
%let i = 1
%macro getdata (dsn);
%do i = 1 %to &N;
data _null_;
	set unique;
	call symputx(cats("date_nbr"),put(intnx('month',today(),-&i,'E'), yyyymmdd.));
run;
data mylib.mth_datasets_&date_key;
	set &dsn;
	where date_key = &date_nbr;
%end;
%mend getdata;
%getdata(mylib.mth_datasets)
5 REPLIES 5
PeterClemmensen
Tourmaline | Level 20

So you want to create 12 individual datasets - one for each of the preceding months, correct?

 

If so, there are better ways to do this.

dkcoop
Fluorite | Level 6

I'm sure there ARE better ways of doing this than what I am doing.  While searching for solutions I've managed to patch together a program that does what I want but if there's a better way I'd love to know it!  

Kurt_Bremser
Super User

I inserted your code into a code box for better readability.

This

data unique;
	set unique;
	id=_N_;
data _null_;
	set unique end=last;
	if last then call symput('N', put(id, 3.));

can be easier done by retrieving the number of obs from DICTIONARY.TABLES:

proc sql noprint;
select nobs into :n from dictionary.tables
where libname = "WORK" and memname = "UNIQUE";
quit;

To use a last date to create a cutoff from a large dataset, do this:

proc sql noprint;
select intnx('month',max(date_key),-12,'b') into : cutoff
from mylib.mth_datasets;
quit;

data want;
set mylib.mth_datasets;
where date_key ge &cutoff.;
/* other code */
run;

Big business-class hint: make it a habit to always end your steps with a RUN statement. Sooner or later an "open" step will cause havoc with the timing of global or macro statements.

dkcoop
Fluorite | Level 6

I tried 

select intnx('month',max(date_key),-12,'b') into : cutoff

But am getting Note "invalid arguument to function intnx missing values may be generated and nothing is returned.  Is it the max function?

Kurt_Bremser
Super User

I am, of course, assuming that your date_key variable contains valid SAS dates, which means it is numeric and has a YYMMDDN8. format attached.

 

With SAS dates, the code works, see here:

data have;
input date_key yymmdd10.;
format date_key yymmdd10.;
datalines;
2021-09-20
2021-08-31
;

proc sql noprint;
select intnx('month',max(date_key),-12,'b') into : cutoff
from have;
quit;

data _null_;
cutoff = &cutoff;
put cutoff yymmdd10.;
run;

Log excerpt:

 82         data _null_;
 83         cutoff = &cutoff;
 84         put cutoff yymmdd10.;
 85         run;
 
 2020-09-01

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!

Register Now

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 5 replies
  • 1583 views
  • 0 likes
  • 3 in conversation