BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Jumboshrimps
Quartz | Level 8

Running the code below, the put statement resolves correctly - "01JUL2025", first day of the month of the LAST quarter. 

I am calling several programs using %include, all requiring the first day of the month of the last quarter.  Need to use it in a data step, so I added the %let statement, that <seems> to repeat the  code directly above.  Get the error messages saying operator requires compatible formats - makes sense the variable "sampdate" is formatted MMDDYY10.   How can I format the variable QSTART as MMDDYY10. - either inside or outside a macro?  Ideally, I'd like to create a correctly formatted global "QSTART" variable before any of the programs run.

 

BONUS QUESTION:  

Will the answer for a data step apply the same qstart variable in PROC SQL?

 


data _null_;
%global qstart ;
qstart = intnx('quarter',date(),-1);
format qstart date9.;
put qstart;
run;

 

%let q_start= intnx('quarter',date(),-1);

 

data tmp;
set safdata.sf;
where sampdate ge "&q_start";
run;

 

LOG:

 


213 data tmp;
214 set safdata.sf;
ERROR: WHERE clause operator requires compatible variables.
215 where sampdate ge "&q_start";
216 run;

 

THANKS.

1 ACCEPTED SOLUTION

Accepted Solutions
Kathryn_SAS
SAS Employee

For your macro variable use the following:

%let q_start= %sysfunc(putn(%sysfunc(intnx(quarter,%sysfunc(date()),-1)),date9.));
%put &q_start;

Then when you used it in the DATA step, use:

data tmp;
set safdata.sf;
where sampdate ge "&q_start"d;
run;

View solution in original post

9 REPLIES 9
Quentin
Super User

short answer: You can just remove the quote marks.

 

Macro variables are all about text substitution.  It's a good idea to look at the value of your macro variables.

 

Below log shows that your macro variable Q_START will resolve to valid SAS code.

 

1    %let q_start= intnx('quarter',date(),-1);
2    %put &=q_start ;
Q_START=intnx('quarter',date(),-1)

In a DATA step with no macro code, you could code:

 

data tmp;
set safdata.sf;
where sampdate ge intnx('quarter',date(),-1) ;
run;

So you could code the same step using your macro variable like:

data tmp;
set safdata.sf;
where sampdate ge &q_start;
run;

 

SampDate is a numeric variable, storing a SAS date (number of days since Jan 1, 1960).  The expression intnx('quarter',date(),-1) will return a numeric value (SAS date for the date that is the start of the prior quarter).

 

Yes, you could use &q_start in PROC SQL.  You could use it anywhere you would like to insert the code intnx('quarter',date(),-1).

Kurt_Bremser
Super User

But the downside of having function calls in macro text is this: the code will be put into the DATA step code, and the function will be called in every DATA step iteration (or for every evaluation of a condition in SQL). 

By using %SYSFUNC, the function is called only once, and a constant value will be written to the code, making it perform faster.

Kathryn_SAS
SAS Employee

For your macro variable use the following:

%let q_start= %sysfunc(putn(%sysfunc(intnx(quarter,%sysfunc(date()),-1)),date9.));
%put &q_start;

Then when you used it in the DATA step, use:

data tmp;
set safdata.sf;
where sampdate ge "&q_start"d;
run;
Kurt_Bremser
Super User

First of all, DATA step functions do NOT work in macro statements on their own. If you want them to work in macro code, you need to use %SYSFUNC:

%let q_start = %sysfunc(intnx(quarter,%sysfunc(date()),-1));

Otherwise the right side of the %LET assignment will be treated as just text.

And if sampdate is a SAS date variable, this will work:

where sampdate ge &q_start.;

For macro variables to be used in code (like here), it's best to have them contain raw, unformatted values. See Maxim 28. Formatting is only needed if used in titles or other places where human-readability is needed.

Tom
Super User Tom
Super User

The %GLOBAL statement makes a symbol (usually called a macro variable) in the GLOBAL symbol table and has nothing to do with actual variables.  There is no such thing as a "global variable" in SAS.  A variable can only exist in a dataset.

 

The macro processor executes while the program text is being read in and before it is passed to the actual SAS language processor.  So placing a %GLOBAL statement in the middle of a data step will just confuse the humans reading the code.  The %GLOBAL statement will be executed by the macro processor before the SAS language processor has finished figuring out how to build the DATA step, and so definitely before the DATA step can run.  So just place the %GLOBAL statement before the DATA statement so it is clearer to the humans reading the code.

 

If you want the data step to set the a value into a macro variable use the CALL SYMPUTX() method.  So this code if run today would put the string 29OCT2025 into a GLOBAL macro variable named QSTART.

data _null_;
  call symputx('qstart',put(intnx('quarter',date(),-1),date9.,'G');
run;

To then use that to generate the WHERE statement in your later code you would need to add something to convert that string into an actual date value.  For example you could use it to generate a date literal.

where sampdate ge "&q_start"d ;

 

PaigeMiller
Diamond | Level 26

Get the error messages saying operator requires compatible formats - makes sense the variable "sampdate" is formatted MMDDYY10.   How can I format the variable QSTART as MMDDYY10. - either inside or outside a macro?  Ideally, I'd like to create a correctly formatted global "QSTART" variable before any of the programs run.

 

I don't think the error message was referring to formats. (Which is why you should always quote the exact error message and always show us the log). It was referring to numeric vs character. You were trying to compare a numeric variable to a character variable, and SAS doesn't know how to do that. Regarding formats, it is possible and even easy to compare date values in format MMDDYY10. to date values in format DATE9. for example, SAS doesn't use the formatted values in its comparisons, it always uses the unformatted values to do arithmetic or logical comparisons.

 

Anyway, as @Kurt_Bremser says, you can use unformatted date values, that works when you do it properly; or as @Tom says, you can use date literals such as '01JAN2020'd, or with a macro variable it would be "&qstart"d where &qstart must have a value that is a proper date literal inside the quotes.

--
Paige Miller
Jumboshrimps
Quartz | Level 8

Yes, that worked in the data step, and also the keep statement.  Also tested in proc sql.

I see some answers use a macro, others use data _null_.

Is there any advantage to data _null_?  These are very short,  declarative statements at the start of a series of programs.   No more than 10-15 lines.

Thanks so much

Kurt_Bremser
Super User

In a DATA _NULL_, you use the functions without the %SYSFUNC wrapper, which makes complicated statements easier to read and maintain. The %LET with %SYSFUNC, OTOH, is pure macro code and can be placed anywhere without breaking other code (e.g. in the middle of a PROC SQL with multiple statements).

Decide which method suits you best in a given situation.

Jumboshrimps
Quartz | Level 8
THX!

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

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
  • 9 replies
  • 753 views
  • 0 likes
  • 6 in conversation