This quick macro displays the format type for a variable. Is there a macro function that will do the same without having to create a null dataset, limit the input file to the first observation and use symput?
29 /*Determine the type of format of a variable in a dataset*/
30 %macro det_format(memname,var_name);
31 data _null_;
32 set &memname(obs=1);
33 call symput('formval',fmtinfo(vformatn(&var_name),'cat'));
34 run;
35
36 %put &formval;
37 %mend;
38 %det_format(dat.AP_455021_9_5,enroll_dt)
MPRINT(DET_FORMAT): data _null_;
MPRINT(DET_FORMAT): set dat.AP_455021_9_5(obs=1);
MPRINT(DET_FORMAT): call symput('formval',fmtinfo(vformatn(enroll_dt),'cat'));
MPRINT(DET_FORMAT): run;
NOTE: There were 1 observations read from the data set DAT.AP_455021_9_5.
NOTE: DATA statement used (Total process time):
real time 0.09 seconds
cpu time 0.00 seconds
date
So you don't want the variable TYPE or the FORMAT attached to the variable.
Instead you want what FMTINFO() calls the CAT or category of the format that is attached.
You can use the VARFMT() function to get the FORMAT specification that is attached.
You can use a little trickery to convert that into the NAME of the format.
You also will probably want to know the TYPE of the variable in case the variable does not have any format specification attached to it.
Everything you need to do this can be retrieved by the VAREXIST() macro.
Let's use SASHELP.STOCKS as our test dataset since it has some different types of variables and different types (categories) or formats attached.
So here is a macro that uses %VAREXIST().
%macro fmtcat(ds,var);
%local format ;
%let format=%varexist(&ds,&var,fmt);
%if %length(&format) %then
%let format=%sysfunc(substrn(&format,1,%sysfunc(findc(&format,.,-49,sdk))))
;
%if %length(&format) %then %sysfunc(fmtinfo(&format,cat));
%else %if %varexist(&ds,&var,type)=C %then char;
%else num;
%mend fmtcat;
So let's test it:
1 %put %fmtcat(sashelp.stocks,stock); char 2 %put %fmtcat(sashelp.stocks,date); date 3 %put %fmtcat(sashelp.stocks,open); curr 4 %put %fmtcat(sashelp.stocks,volume); num
Is there a reason you can't use dictionary.columns?
proc sql;
select
name
, type
from
dictionary.columns
where
libname = "SASHELP"
and memname = "CARS";
quit;
Or even PROC CONTENTS?
What is the purpose of the macro variable?
If you need to, you can still place it in a macro variable.
proc sql;
select
type
from
dictionary.columns
where
libname = "SASHELP"
and memname = "CARS"
and name = "MSRP";
quit;
Sorry, it will give the type as "num" or "char" but not "date"
My apologies - sometimes I read too quickly.
data want;
x = TODAY();
format x yymmddn8.;
run;
proc sql;
select
format
from
dictionary.columns
where
libname = "WORK"
and memname = "WANT";
quit;
The is no variable type "date" in SAS. The only variable types in SAS are number or text (character).
A variable can be treated as a date if the human programmer uses DATE functions, formats and informats on the variable. SAS thinks it is simply a number.
Actually, the fmtinfo does give the format type (see my example in the first post on this topic). I'm just looking for a way to generate the result without having to run a data step.
You can retrieve the format name from DICTIONARY.COLUMNS, and then use the FMTINFO function with %SYSFUNC.
@Kurt_Bremser wrote:
You can retrieve the format name from DICTIONARY.COLUMNS, and then use the FMTINFO function with %SYSFUNC.
But DICTIONARY.COLUMNS does not have the format name. It has the full format specification. And FMTINFO() only works with the bare name. See above for algorithm to extract the format name from a format specification.
So you don't want the variable TYPE or the FORMAT attached to the variable.
Instead you want what FMTINFO() calls the CAT or category of the format that is attached.
You can use the VARFMT() function to get the FORMAT specification that is attached.
You can use a little trickery to convert that into the NAME of the format.
You also will probably want to know the TYPE of the variable in case the variable does not have any format specification attached to it.
Everything you need to do this can be retrieved by the VAREXIST() macro.
Let's use SASHELP.STOCKS as our test dataset since it has some different types of variables and different types (categories) or formats attached.
So here is a macro that uses %VAREXIST().
%macro fmtcat(ds,var);
%local format ;
%let format=%varexist(&ds,&var,fmt);
%if %length(&format) %then
%let format=%sysfunc(substrn(&format,1,%sysfunc(findc(&format,.,-49,sdk))))
;
%if %length(&format) %then %sysfunc(fmtinfo(&format,cat));
%else %if %varexist(&ds,&var,type)=C %then char;
%else num;
%mend fmtcat;
So let's test it:
1 %put %fmtcat(sashelp.stocks,stock); char 2 %put %fmtcat(sashelp.stocks,date); date 3 %put %fmtcat(sashelp.stocks,open); curr 4 %put %fmtcat(sashelp.stocks,volume); num
You might also like the TYPEF variable created by this %CONTENTS() macro.
Example:
%contents(sashelp.stocks,out=contents);
proc print;
run;
Results
Obs libname memname varnum name length typen type typef format informat formatn formatl formatd informn informl informd 1 SASHELP STOCKS 1 Stock 9 2 char char 0 0 0 0 2 SASHELP STOCKS 2 Date 8 1 num date DATE. DATE. DATE 0 0 DATE 0 0 3 SASHELP STOCKS 3 Open 8 1 num curr DOLLAR8.2 BEST32. DOLLAR 8 2 BEST 32 0 4 SASHELP STOCKS 4 High 8 1 num curr DOLLAR8.2 BEST32. DOLLAR 8 2 BEST 32 0 5 SASHELP STOCKS 5 Low 8 1 num curr DOLLAR8.2 BEST32. DOLLAR 8 2 BEST 32 0 6 SASHELP STOCKS 6 Close 8 1 num curr DOLLAR8.2 BEST32. DOLLAR 8 2 BEST 32 0 7 SASHELP STOCKS 7 Volume 8 1 num num COMMA12. BEST32. COMMA 12 0 BEST 32 0 8 SASHELP STOCKS 8 AdjClose 8 1 num curr DOLLAR8.2 BEST32. DOLLAR 8 2 BEST 32 0 Obs label nvar nobs crdate modate typemem memtype memlabel 1 8 699 06SEP2017:23:02:27 06SEP2017:23:02:27 DATA Performance of Three Stocks from 1996 to 2005 2 8 699 06SEP2017:23:02:27 06SEP2017:23:02:27 DATA Performance of Three Stocks from 1996 to 2005 3 8 699 06SEP2017:23:02:27 06SEP2017:23:02:27 DATA Performance of Three Stocks from 1996 to 2005 4 8 699 06SEP2017:23:02:27 06SEP2017:23:02:27 DATA Performance of Three Stocks from 1996 to 2005 5 8 699 06SEP2017:23:02:27 06SEP2017:23:02:27 DATA Performance of Three Stocks from 1996 to 2005 6 8 699 06SEP2017:23:02:27 06SEP2017:23:02:27 DATA Performance of Three Stocks from 1996 to 2005 7 8 699 06SEP2017:23:02:27 06SEP2017:23:02:27 DATA Performance of Three Stocks from 1996 to 2005 8 Adjusted Close 8 699 06SEP2017:23:02:27 06SEP2017:23:02:27 DATA Performance of Three Stocks from 1996 to 2005
data stocks;
set sashelp.stocks ;
format stock $40.;
run;
%let dsn= stocks ;
%let vname= stock ;
%let dsid=%sysfunc(open(&dsn.));
%let var_n=%sysfunc(varnum(&dsid.,&vname.));
%let var_fmt=%sysfunc(prxchange(s/[\.\d]+$//,1,%sysfunc(varfmt(&dsid.,&var_n.))));
%let fmt_type=%sysfunc(fmtinfo(&var_fmt.,cat));
%let dsid=%sysfunc(close(&dsid.));
%put &=var_n. &=var_fmt. &=fmt_type.;
Why did you attach the $ format to STOCK? It is just a normal character variable it does not need to have a format attached.
Why did you remove all of the digits from the format value? That would convert something like S370FRB8. (which is a valid SAS supplied numeric format specification) to SFRB which is not a SAS supplied format name.
By default, there is no FORMAT attached with STOCK as showed in your picture. Otherwise,my code would get a NULL value .
P.S. since OP only need the FORMAT , So no need to consider the variable on which there is no format.
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
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.
Ready to level-up your skills? Choose your own adventure.