Using Functions SYSFUNC and IFC to Conditionally Execute Statements in Open Code

Using Functions SYSFUNC and IFC to Conditionally Execute Statements in Open Code

Ronald J. Fehd, Centers for Disease Control and Prevention, Atlanta, GA, USA

                                                                                                                          ——SAS Global Forum 2009

Introduction
Overview Program development proceeds through these stages:
 create ad hoc programs
 identify programs with similar algorithms
 consolidate into parameterized include program
 where necessary, convert to macro for conditional processing
The techniques shown here eliminate the need for macros and replace conditional processing with inline statements.
Example: %if statement used to conditionally execute blocks of code.
%macro DoThis;
%if <condition> %then %do;
       * statements for true;
       %end;
%else %do;
        * statements for false;
%end;
run;%mend;
%DoThis


can be replaced with this:
%sysfunc(ifc(<condition>
                ,* statements for true;
                ,* statements for false;
))

Function IFC

Data Step Function IFC
The ifc function has four parameters:
1. a logical expression
2. character value returned when true
3. value returned when false
4. value returned when missing, which is optional

 

IFC syntax

 IFC( logical-expression
       , value-returned-when-true
       , value-returned-when-false
     <, value-returned-when-missing>
       )

This example shows the function in a data step.

DATA Work.TestIfc;
attrib N        length = 4
          Value length = $ %length(missing);
do  N = ., 0, 1, -1;
      Value = ifc(N
                     ,’true’
                     ,’false’
                     ,’missing’
                     );
       output;
       end;
 stop;
 run;

Proc Print data = Work.TestIfc
;

 

Function SysFunc

Macro Function SysFunc SysFunc and GetOption

The macro function sysfunc provides a method to access certain data step functions and the values of options.


This example shows the combination of sysfunc and getoption writing a note to the log with the value of the option source2.

     options nosource2;
     %Put option source2 is %sysfunc(getoption(source2));
option source2 is NOSOURCE2
     options source2;
     %Put option source2 is %sysfunc(getoption(source2));
option source2 is SOURCE2

 

SysFunc and IFC

Macro Statement PUT with IFC

This example contains the previous usage of sysfunc and getoption. Its purpose is to show that the evaluation of the logical expression can produce conditional text.

options nosource2;
%Put option source2 is
%sysfunc(ifc(%sysfunc(getoption(source2)) eq SOURCE2
                 ,True
                 ,False
                 ,Missing
           )      );
option source2 is False

Note that the sysfunc(ifc(...)) is within the %put statement whose ending semicolon is on log line 7.

 

IFC producing PUT

The promise of sysfunc(ifc(...)) is to generate statements, based on the evaluation.

This example shows the first test: a complete %put statement as the result of the evaluation.

The Error:

options nosource2;
%sysfunc(ifc(%sysfunc(getoption(source2)) eq SOURCE2
                 ,%Put True;
True
                 ,%Put False;
False
                 ,%Put Missing;
Missing
                 ))

What happened here? All the macro %put statements were executed!

Nrstr of PUT:

The statements must be wrapped in macro function nrstr (No Rescan String) which delays their execution
until after the ifc condition has been evaluated.

options nosource2;
 %sysfunc(ifc(%sysfunc(getoption(source2)) eq SOURCE2
                   ,%nrstr(%Put True;)
                   ,%nrstr(%Put False;)
                   ,%nrstr(%Put Missing;)
             )     )
False

Note that the sysfunc(ifc(...)) is not a statement; the function calls are completed by the two closing parentheses on log line 6.

Usage Examples

Overview

These are common tests:
 boolean: zero, one or greater than one
 comparison of two values
 existence

Boolean

Many functions return either the set of boolean values — (0,1) — or zero and a negative or positive integer which evaluates as true. Remember that true is not false .
          0,1 : %sysfunc(cexist(&Catalog.))
    0, ge 1 : &Nobs.
-1,0, ge 1 : %sysfunc(attrn(&dsid.,nobs))

comparison

Any logical expression can be used for the first argument of the ifc function.
 &NobsData1. eq &NobsData2.
 &Nobs. gt 100
 %sysfunc(fileref(&FileRef.)) eq 0
 %upcase(%substr(&Type.,1,1)) eq C or &Type. eq 2
There are pitfalls when comparing user-supplied values; refer to Fehd [2],
sas-wiki.Cond-Exec-Global-Stmnts for examples and fixes.

Test Suite

Each of the following programs has been tested as a parameterized include file, illustrated by this example:

options source2;
Proc Format library = Work; value Test 0=’zero’;run;
%Let Catalog = Work.Formats;
%Include Project(assert-cexist-catalog);
%Let Catalog = Library.Formats;
%Include Project(assert-cexist-catalog);

Calling Routines

Branching with Includes

Evaluation of the logical expression can be used to branch to the execution of either of two programs.* cond-inc-which;
options source2;
%Let Data = sashelp.Class;
%Let Data = sashelp.ClassX;
%let dsid = %sysfunc(open(&Data. ));
%let Nobs =
%sysfunc(ifc(&DsId.
            ,%nrstr(            %sysfunc(attrn(&dsid.,nobs));
                    %let rc   = %sysfunc(close(&dsid.)); )
            ,%nrstr(0) ));
%sysfunc(ifc(&Nobs.
            ,%nrstr(%Include Project(cond-inc-1);)
            ,%nrstr(%Include Project(cond-inc-0);) ))

%Put Note2: file is cond-inc-0;
%Put Note2: file is cond-inc-1;


Procedure By Type

The elaborate test of the value of Type ensures that this code can be called with a list processing data set created by either Proc Contents whose Type are in (1,2) and Proc SQL whose Type are in (’char’,’num’).

title3 "proc-type of &Libname..&Memname.;";
%sysfunc(ifc( %upcase(%substr(&Type.,1,1)) eq C
                    or &Type eq 2
                    ,%nrstr(Proc Freq data = &Libname..&Memname.;
                                             tables &Name.;)
                    ,%nrstr(Proc Means data = &Libname..&Memname.;
                                               var &Name.;) ))
run;

Calling Proc-Type

This code is similar to the conditional processing in the SmryEachVar data review suite Fehd ,sgf2008.003.

****proc-type-Test.sas****;

options source2;
%Let Libname = sashelp;
%Let Memname = Class;
%Let Name = Sex;
%Let Type = C;
%Include Project(proc-type);

%Let Name = Height;
%Let Type = 1;
%Include Project(proc-type);

****proc-type-caller-SQL.sas***;

options source2;
%Let Libname = sashelp;
%Let Memname = Class;
Proc SQL; select catt(’%let Name =’,Name,’;’
                             , ’%let Type =’,Type,’;’
                             ,’%Include Project(proc-type)’)
              into :List separated by ’;’

              from Dictionary.Columns
             where Libname eq "%upcase(&Libname.)"
                      and Memname eq "%upcase(&Memname.)"
                     and Memtype eq ’DATA’;
   quit;
&List.

****proc-type-caller-Contents.sas********;
 options source2;
 %Let Libname = sashelp;
 %Let Memname = Class;
 Proc Contents data = &Libname..&Memname.
                               noprint
                     out = Work.Contents;
DATA _Null_;
attrib Stmnt length = $72;
do until(EndoFile);
    set Work.Contents end = EndoFile;
    Stmnt = catt(’%Let Name =’,Name,’;’);
    link ExecStmt;
    Stmnt = catt(’%Let Type =’,Type,’;’);
    link ExecStmt;
    Stmnt = ’%Include Project(proc-type);’;
    link ExecStmt;
    end;

return;
ExecStmt: call execute(catt(’%nrstr(’,Stmnt,’)’));
return;
stop;
run;

Number of Rows

The attrn function can be used to get the number of observations of a data set. The data set must be opened before the function can return the value. If the data set exists then the function can be applied; otherwise
when the open of the data set fails, it is not necessary to close the data set.
The values returned by attrn(...,nobs) are in:
   -1 : for a view
    0 : empty
ge 1 : number of rows

*****assert-nobs.sas************;
 %let dsid = %sysfunc(open(&Data. ));
 %let Nobs =
 %sysfunc(ifc(&DsId.
                   ,%nrstr( %sysfunc(attrn(&dsid.,nobs));
                               %let rc = %sysfunc(close(&dsid.)); )
                   ,%nrstr(0) ));
 %sysfunc(ifc(&Nobs.
                  ,%nrstr(%Put Note2: Data &Data. Nobs: &Nobs.;)
                  ,%nrstr(%Put %sysfunc(sysmsg());
                            endSAS;) ))

该文初稿:

http://www.sascommunity.org/wiki/Conditionally_Executing_Global_Statements#Assert_Nobs_or_Nvars

你可能感兴趣的:(function,processing,Parameters,character,include,macros)