Would you like to format your macro variables?
Easy! Just use the %FORMAT function, like this:
What?! You never heard of the %FORMAT function?
Of course not, cuz it doesn't exist! No problem.
Just create it, like this:
%macro format(value,format); %if %datatyp(&value)=CHAR %then %sysfunc(putc(&value,&format)); %else %left(%qsysfunc(putn(&value,&format))); %mend format; |
The %FORMAT function also accepts user-defined formats, like this:
The PROC SQL step below creates the macro variable HIGHSALARY, which is referenced in the TITLE statement and formatted with the user-defined %FORMAT function.
proc sql noprint; select 5*avg(salary) into :highsalary from orion.staff; reset print; title "Salaries over %format(&highsalary,dollar11.2)"; select employee_ID, salary from orion.staff where salary > &highsalary order by salary desc; quit; |
Be sure to save your user-defined %FORMAT function in your stored compiled macro or autocall library for convenient re-use!
If you enjoyed this tip on how to format a macro variable in SAS, and want more like it, consider taking our SAS Macro Language 1: Essentials course and/or our SAS Macro Language 2: Advanced Techniques, offered in the classroom, as Live Web classes, or as self-paced e-Learning. These courses are part of our SAS Programming curriculum.
You can also find more programming tips here. And, check back often. New tips, from a variety of SAS blogs, are added regularly!
11 Comments
Great!
I suggest add a "strip" to remove the tailing blank character.
%macro format(value,format);
%if %datatyp(&value)=CHAR
%then %sysfunc(strip(%sysfunc(putc(&value,&format))));
%else %left(%qsysfunc(putn(&value,&format)));
%mend format;
How do I convert a macro variable from character to numeric?
Michele, the bad news is you cannot, but the good news is you never need to. Consider these examples ...
%let x=3;
%put y=%eval(&x+&x);
data a;
z=&x;
run;
In the first example, y is 6.
In the second example, z is a numeric variable.
Macro variable x remains character.
Cheers,
Jim
proc contents;
run;
Q.1 How to get date9. format for cutoff_stdat variable , kindly help.
%let cutoff_stdt = 19MAY2019:00:00:00.000 ;
%let cutoff_stdat= %sysfunc(inputn(&cutoff_stdt.,DATETIME22.3)) ;
%put &cutoff_stdat. ; /* Tried %put %format (&cutoff_stdat , date9. ) ; */
%let cutoff_stdt=19MAY2019:00:00:00.000;
%let cutoff_stdat=%sysfunc(inputn(&cutoff_stdt.,DATETIME22.3)) ;
%put &cutoff_stdat.;
%put %sysfunc(putn(&cutoff_stdat,DATETIME22.3));
%let dateonly=%sysfunc(datepart(&cutoff_stdat));
%put %sysfunc(putn(&dateonly,DATE9.));
I am sorry, but I have to add more water to the wine.
On top of what Quentin pointed out already (potential quoting problems), the data type is derived from the value. Well, the caller has to provide the data type-specific format name, anyways.
And now try
%put %format(123,$3.);
The helper macro will generate a putn() call which will FAIL with the char format.
Instead of using %datatyp() it should inspect 1st char of the format name.
Clever idea, Jim. I want to point out a subtle aspect of Jim's example that might not be apparent. Namely, the example shows a single procedure that assigns a macro variable and then immediately uses the (formatted) macro variable in a global statement (TITLE). This works for PROC SQL because SQL is an INTERACTIVE procedure, which means that each statement is executed as it is encountered. Similarly, the same idea would work in PROC IML. However, in the DATA step, the macro variable is not created until after the DATA step exits. That means that you would need to put the TITLE statement after the RUN statement that ends the step. Here is an example:
%symdel pi / nowarn;
title;
data _null_;
call symputx("pi", 3.14159);
shortPi = "%format(&pi, 5.2)"; /* ERROR: macro var not defined yet */
run;
%put &=pi;
title "pi = %format(&pi, 5.2)"; /* macro var is now defined */
Rick is spot on. I chose PROC SQL for its ability to:
1) Calculate a statistic
2) Store the statistic into a macro variable
3) Produce a report
... all in a single step!
Are there other ways? Of course!
proc means data=orion.staff noprint;
var salary;
output out=mystats mean=avgsal;
run;
data _null_;
set mystats;
call symputx('meansalary',avgsal);
run;
proc print data=orion.staff;
where salary > &meansalary;
title "Salaries over %format(&meansalary,dollar11.2)";
run;
But that's three steps! I'll almost always choose one step over three!
Nifty. To protect against macro triggers inside a format value (e.g. value 1='Tom&Jerry'), maybe it would be a good idea to macro quote the returned value, by using %qsysfunc and %qleft, like:
%if %datatyp(&value)=CHAR %then %qsysfunc(putc(&value,&format)); %else %qleft(%qsysfunc(putn(&value,&format)));
Where is the %datatype macro
%DATATYP is an autocall macro shipped with BASE SAS software. You can find it here ...
http://go.documentation.sas.com/?cdcId=pgmsascdc&cdcVersion=9.4_3.2&docsetId=mcrolref&docsetTarget=p14qy9r4wu1an0n11kfn30idvy20.htm&locale=en