Thursday, January 22, 2009

How to check format exist?

The popular method to identify the format is using dictionary tables (catalogs and formats).
What is the difference between them?
If you check the existence only from the format searchpath, dictionary.formats is the key. Otherwise, you can get ALL formats using dictionary.catalogs.

proc sql;
select libname, memname, objname
from dictionary.catalogs
where objtype contains 'FORMAT' and objname = 'FMTNAME' ;

proc sql;
select libname, memname, objname
from dictionary.formats
where objname = 'FMTNAME' ;
quit;

Wednesday, January 21, 2009

a special function for %sysfunc world: filename function

Below are the code from SAS online doc:
%let filrf=myfile;
%let rc=%sysfunc(filename(filrf, physical-filename));
%if &rc ne 0 %then
%put %sysfunc(sysmsg());
%let rc=%sysfunc(filename(filrf));

It should be noted that the fileref is "myfile", not "filerf". That means the macro variable "filerf" contains the ACTUAL fileref.
When the macro variable does not exist, the system generates a fileref automatically.

It seems that it is unique to filename function.
For now, I have not found any other functions which can take the similar behavior.

Note that it will not work if the fileref has been assigned. For more information, please see http://support.sas.com/kb/6/567.html

Thursday, January 15, 2009

macro autocall

Here are sample codes for macro autocall.
Personally, I perfer "fileref" type because it is flexible.

/* fileref */
filename utility catalog "lib.catalog";
*filename utility "c:\utility";
options mautosource mrecall sasautos=(sasautos utility);

/* libref */
libname utility "c:\utility";
options mautosource mrecall sasautos=(sasautos utility);

/* host-specific path;*/
options mautosource mrecall sasautos=(sasautos "c:\utility");

Tuesday, January 13, 2009

By-Group value in title statement

By default, by-group values (#byvar, #byval and #byline) in the title statement can not change among by-groups. It is reasonable since the by-group section in the procedure output should be regarded as a whole. And title statement is for the whole output, not every by-group section.

Online doc says below
"Use NOBYLINE to suppress the automatic printing of BY lines in procedure output. You can then use #BYVAL, #BYVAR, or #BYLINE to display BYLINE information in a TITLE statement."

That means the new procedure output with NOBYLINE will be splitted into several by-group sections, and every section is regarded as a whole seperately. In this way, the by-group section should have its own title.

Sample code:

proc sort data=sashelp.class out=class;
by sex;
run;

options nobyline; *trick here;
ods html file="test.htm";
proc print data=class;
title "Subject list - #byval1";
var name sex height weight;
by sex;
run;
ods html close;

However, the trick is not necessary for graph output since every graph output is a whole actually. It should be noted that goption HBY=0 can also suppress byline in graph output.

Sample code:

options byline;
goptions hby=0;
proc gplot data=class;
by sex;
plot height*weight;
run;

For more control for byline style, please see http://support.sas.com/kb/23/325.html

Sunday, January 4, 2009

CALL EXECUTE change the "macro execution path"

As for CALL EXECUTE, SAS Manual says that
"If argument resolves to a macro invocation, the macro executes immediately and DATA step execution pauses while the macro executes. If argument resolves to a SAS statement or if execution of the macro generates SAS statements, the statement(s) execute after the end of the DATA step that contains the CALL EXECUTE routine."

And it is interesting that the macro execution path are different for CALL EXECUTE type and standard type.

Standard type executes Macro language (statement, function, variable) and SAS statements step by step. However, CALL EXECUTE type do NOT execute SAS statement, which are created by macro, but put them after the end of that DATA step.

Sample code:

%macro test(a);
%let b=2;
%put 1> a is "&a" and b is "&b";
data _null_;
put "2> a is '&a' and b is '&b'";
call symput('b', '3');
run;

%put 3> a is "&a" and b is "&b";
%mend;

* Standard Type;
%test(1)

* Output:
1> a is "1" and b is "2"
2> a is '1' and b is '2'
3> a is "1" and b is "3"
;


* CALL EXECUTE Type;
data _null_;
call execute('%test(1)');
run;

* Output:
1> a is "1" and b is "2"
3> a is "1" and b is "2"
2> a is '1' and b is '2'
;