Processing Statements Conditionally

Conditional Execution

You can use macros to control conditional execution of statements. Remember the example from the beginning of this chapter where you wanted to run a daily report to create registration listings for courses to be held later in the month. Remember that you also wanted to run a weekly report each Friday to create a summary of revenue that has been generated so far in the current month. You can accomplish these tasks with one program if you use conditional execution to determine whether the second report should be run.
You can perform conditional execution at the macro level with %IF-%THEN and %ELSE statements.
General form, %IF-%THEN and %ELSE statements:
%IF expression %THEN text;
<%ELSE text;>
Here is an explanation of the syntax:
expression
can be any valid macro expression that resolves to an integer.
text
can be specified as
  • constant text
  • a text expression
  • a macro variable reference, a macro call, or a macro program statement.
If expression resolves to zero, then it is false and the %THEN text is not processed (the optional %ELSE text is processed instead). If it resolves to any integer other than zero, then the expression is true and the %THEN text is processed. If it resolves to null or to any noninteger value, an error message is issued.
The %ELSE statement is optional. However, the macro language does not contain a subsetting %IF statement. Thus, you cannot use %IF without %THEN.

%IF-%THEN Compared to IF-THEN

Although they look similar, the %IF-%THEN/%ELSE statement and the IF-THEN/ELSE statement belong to two different languages. Most of the same rules that apply to the DATA step IF-THEN/ELSE statement also apply to the %IF-%THEN/%ELSE statement. However, there are several important differences between the macro %IF-%THEN statement and the DATA step IF-THEN statement.
%IF-%THEN...
IF-THEN...
is used only in a macro program.
is used only in a DATA step program.
executes during macro execution.
executes during DATA step execution.
uses macro variables in logical expressions and cannot refer to DATA step variables in logical expressions.
uses DATA step variables in logical expressions.
determines what text should be copied to the input stack.
determines what DATA step statement(s) should be executed. When inside a macro definition, it is copied to the input stack as text.
Simple %DO and %END statements often appear in conjunction with %IF-%THEN/%ELSE statements in order to designate a section of the macro to be processed depending on whether the %IF condition is true or false. Use %DO and %END statements following %THEN or %ELSE in order to conditionally place text that contains multiple statements onto the input stack. Each %DO statement must be paired with an %END statement.
General form, %DO-%END with %IF-%THEN and %ELSE statements:
%IF expression %THEN %DO;
text and/or macro language statements
%END;
%ELSE %DO;
text and/or macro language statements
%END;
Here is an explanation of the syntax:
text and/or macro language statements
is either constant text, a text expression, and/or a macro statement.
Note: The statements %IF-%THEN, %ELSE, %DO, and %END are macro language statements that can be used only inside a macro program.

Example

You can control text that is copied to the input stack with the %IF-%THEN while controlling DATA step logic with IF-THEN. In this example, the value of the macro variable status determines which variables are included in the new data set. The value of the data set variable Location determines the value of the new data set variable Totalfee.
%macro choice(status);
   data fees;
      set sasuser.all;
      %if &status=PAID %then %do;
         where paid='Y';
         keep student_name course_code begin_date totalfee;
      %end;
      %else %do;
         where paid='N';
         keep student_name course_code
              begin_date totalfee latechg;
         latechg=fee*.10;
      %end;
      /* add local surcharge */
      if location='Boston' then totalfee=fee*1.06;
      else if location='Seattle'  then totalfee=fee*1.025;
      else if location='Dallas'  then totalfee=fee*1.05;
   run;
%mend choice;
If the MPRINT and MLOGIC system options are both set, the SAS log displays messages showing the text that is sent to the compiler. For example, suppose you submit the following macro call:
options mprint mlogic;
%choice(PAID)
The following messages are written to the log. Notice that the MLOGIC option shows the evaluation of the expression in the %IF statement, but it does not show the evaluation of the expression in the IF statement.
Table 11.12 SAS Log
160  %choice(PAID)
MLOGIC(CHOICE): Beginning execution.
MLOGIC(CHOICE): Parameter STATUS has value PAID
MPRINT(CHOICE): data fees;
MPRINT(CHOICE): set sasuser.all;
MLOGIC(CHOICE): %IF condition &status=PAID is TRUE
MPRINT(CHOICE): where paid='Y';
MPRINT(CHOICE): keep student_name course_code begin_date totalfee;
MPRINT(CHOICE): if location='Boston' then totalfee=fee*1.06;
MPRINT(CHOICE): else if location='Seattle' then totalfee=fee*1.025;
MPRINT(CHOICE): else if location='Dallas' then totalfee=fee*1.05;
MPRINT(CHOICE): run;
Suppose you submit the following macro call:
options mprint mlogic;
%choice(OWED)
The following messages are sent to the SAS log. Notice that the text that is written to the input stack is different this time.
Table 11.13 SAS Log
161  %choice(OWED)
MLOGIC(CHOICE): Beginning execution.
MLOGIC(CHOICE): Parameter STATUS has value OWED
MPRINT(CHOICE): data fees;
MPRINT(CHOICE): set sasuser.all;
MLOGIC(CHOICE): %IF condition &status=PAID is FALSE
MPRINT(CHOICE): where paid='N';
MPRINT(CHOICE): keep student_name course_code begin_date totalfee
                latechg;
MPRINT(CHOICE): latechg=fee*.10;
MPRINT(CHOICE): if location='Boston' then totalfee=fee*1.06;
MPRINT(CHOICE): else if location='Seattle' then totalfee=fee*1.025;
MPRINT(CHOICE): else if location='Dallas' then totalfee=fee*1.05;
MPRINT(CHOICE): run;
Earlier you learned the process that occurs when a macro program is compiled. Now that you have seen more-complex macro programs, we can examine this process again.
Remember that during macro compilation, macro statements are checked for syntax errors. If a macro definition contains macro statement syntax errors, error messages are written to the SAS log, and a non-executable (dummy) macro is created.

Example

Suppose you attempt to compile a macro that contains a syntax error. For example, the following program is missing a percent sign in the %IF-%THEN statement:
%macro printit;
   %if &syslast ne _NULL_ then %do;
      proc print data=_last_(obs=5);
      title "Last Created Data Set Is &syslast";
      run;
   %end;
%mend;
When you submit this macro definition, the macro processor checks the %IF-%THEN statement and the %DO and %END statements for syntax errors. Since there is a syntax error in the %IF-%THEN statement, the following error messages are written to the SAS log.
Table 11.14 SAS Log
10   %macro printit;
11     %if &syslast ne _NULL_ then %do;
ERROR: Macro keyword DO appears as text. A semicolon or other
       delimiter may be missing.
ERROR: Expected %THEN statement not found. A dummy macro will be
       compiled.
12         proc print data=_last_(obs=5);
13         title "Last Created Data Set Is &syslast";
14         run;
15     %end;
ERROR: There is no matching %DO statement for the %END. This
      statement will be ignored.
16  %mend;

Macro Execution with Conditional Processing

Earlier you learned that when the macro processor receives %macro-name, it executes compiled macro language statements such as %IF-%THEN. The values of macro variables that are used within the %IF logical expression are resolved during macro execution. The %IF logical expression is automatically evaluated.

Example

Suppose the Printit macro has been compiled and has been stored in the Work.Sasmacr catalog.
  1. First, you submit a call to the Printit macro, as follows:
    %printit
  2. The macro processor locates the macro in the SAS catalog Work.Sasmacr.
    Catalog Entry Work.Sasmacr.Printit.Macro
    %macro printit;
       %if &syslast ne _NULL_ %then %do;
          proc print data=_last_(obs=5);
          title "Last Created Data Set Is &syslast";
          run;
       %end;
    %mend;
  3. The macro processor begins to execute compiled macro language statements from Printit (that is, the %IF-%THEN statement). Because the %IF expression is true, the %DO block is processed.
  4. The macro processor places the text that follows the %DO statement (that is, the PROC PRINT step) on the input stack.
    Input Stack
    proc print data=_last_(obs=5);
       title "Last Created Data Set Is &syslast";
    run;
  5. Word scanning proceeds as usual on the PROC PRINT step. When a macro trigger such as &syslast is encountered, the macro reference is passed to the macro processor for resolution. The macro processor returns resolved values to the input stack.
  6. After the word scanner sends all of the tokens from the PROC PRINT step to the compiler, and the RUN statement is encountered, the PROC PRINT step executes.
  7. Macro execution pauses while the PROC PRINT step executes, and macro execution stops when the %MEND statement is encountered.
It is possible to conditionally insert individual statements into the input stack, even in the middle of a step.

Example

Suppose you want to generate a report of enrollment at each training center as listed in the data set Sasuser.All. You can specify your macro program so that if a specific course is requested, the macro inserts a WHERE ALSO statement in order to restrict the report to that course. This example also customizes the second title line based on whether a course was selected, as follows:
%macro attend(crs,start=01jan2001,stop=31dec2001);
   %let start=%upcase(&start);
   %let stop=%upcase(&stop);
   proc freq data=sasuser.all;
      where begin_date between "&start"d and "&stop"d;
      table location / nocum;
      title "Enrollment from &start to &stop";
      %if &crs= %then %do;
         title2 "for all Courses";
      %end;
      %else %do;
         title2 "for Course &crs only";
         where also course_code="&crs";
      %end;
   run;
%mend;
Note: In the program above, the %IF statement %if &crs= is true when crs has a value of null.
Suppose you submit the following call, which specifies a specific course:
%attend(C003)
This call results in the following output. Notice that the second title has been written according to the %ELSE %DO statement in the macro.
FREQ Procedure Output
Table 11.15 SAS Log
18   %attend(C003)
MPRINT(ATTEND):   proc freq data=sasuser.all;
MPRINT(ATTEND):   where begin_date between "01JAN2001"d and "31DEC2001"d;
MPRINT(ATTEND):   table location / nocum;
MPRINT(ATTEND):   title "Enrollment from 01JAN2001 to 31DEC2001";
MPRINT(ATTEND):   title2 "for Course C003 only";
MPRINT(ATTEND):   where also course_code="C003";
NOTE: WHERE clause has been augmented.
MPRINT(ATTEND):   run;

NOTE: Writing HTML Body file: sashtml.htm
NOTE: There were 2 observations read from the data set SASUSER.SCHEDULE.
      WHERE (Course_Code='C003') and (Begin_Date>='01JAN2001'D and 
                                                Begin_Date<='31DEC2001'D);
NOTE: There were 207 observations read from the data set SASUSER.STUDENTS.
NOTE: There were 434 observations read from the data set SASUSER.REGISTER.
NOTE: There were 1 observations read from the data set SASUSER.COURSES.
      WHERE Course_Code='C003';
NOTE: There were 50 observations read from the data set SASUSER.ALL.
      WHERE (begin_date>='01JAN2001'D and begin_date<='31DEC2001'D) 
                                                 and (course_code='C003'),
Now suppose you submit the following call, which specifies a start date but does not specify a course:
%attend(start=01jul2001)
This call results in the following output. Notice that in this output, the second title line is written according to the %IF-%THEN statement in the macro.
Enrollment output
Table 11.16 SAS Log
19   %attend(start=01jul2001)
MPRINT(ATTEND):   options mprint;
MPRINT(ATTEND):   proc freq data=sasuser.all;
MPRINT(ATTEND):   where begin_date between "01JUL2001"d and "31DEC2001"d;
MPRINT(ATTEND):   table location / nocum;
MPRINT(ATTEND):   title "Enrollment from 01JUL2001 to 31DEC2001";
MPRINT(ATTEND):   title2 "for all Courses";
MPRINT(ATTEND):   run;

NOTE: There were 6 observations read from the data set SASUSER.SCHEDULE.
      WHERE Course_Code in ('C001', 'C002', 'C003', 'C004', 'C005', 'C006') and
      (Begin_Date>='01JUL2001'D and Begin_Date<='31DEC2001'D);
NOTE: There were 207 observations read from the data set SASUSER.STUDENTS.
NOTE: There were 434 observations read from the data set SASUSER.REGISTER.
NOTE: There were 6 observations read from the data set SASUSER.COURSES.
NOTE: There were 162 observations read from the data set SASUSER.ALL.
      WHERE (begin_date>='01JUL2001'D and begin_date<='31DEC2001'D);

Conditional Processing of Parts of Statements

The text that is processed as the result of conditional logic can be a small part of a SAS statement. This makes it possible to conditionally insert text into the middle of a statement.

Example

Suppose you want to print a table of frequency counts from a SAS data set. You can generate either a one-way table or a two-way table, based on the value of a macro parameter. This example creates a one-way table if only the cols parameter is specified in the call. It creates a two-way table if the rows parameter is also specified.
%macro counts (cols=_all_,rows=,dsn=&syslast);
   title "Frequency Counts for %upcase(&dsn) data set";
   proc freq data=&dsn;
      tables
      %if &rows ne %then &rows *;
      &cols;
   run;
%mend counts;
Suppose you submit the following call, which specifies both cols and rows:
%counts(dsn=sasuser.all, cols=paid, rows=course_number)
Part of the resulting output from this call is shown below. Notice that the macro has created a two-way table.
Frequency Counts
The log shows the generated PROC FREQ code from this macro.
Table 11.17 SAS Log
28   %counts(dsn=sasuser.all, cols=paid, rows=course_number)
MPRINT(COUNTS):   title "Frequency Counts for SASUSER.ALL data set";
MPRINT(COUNTS):   proc freq data=sasuser.all;
MPRINT(COUNTS):   tables course_number * paid;
MPRINT(COUNTS):   run;

NOTE: There were 18 observations read from the data set SASUSER.SCHEDULE.
      WHERE Course_Code in ('C001', 'C002', 'C003', 'C004', 'C005', 'C006'),
NOTE: There were 207 observations read from the data set SASUSER.STUDENTS.
NOTE: There were 434 observations read from the data set SASUSER.REGISTER.
NOTE: There were 6 observations read from the data set SASUSER.COURSES.
NOTE: There were 434 observations read from the data set SASUSER.ALL.
NOTE: PROCEDURE FREQ used (Total process time):
Now suppose you submit the following call, which specifies cols but does not specify rows:
%counts(dsn=sasuser.all, cols=paid)
The output that results from this call is shown below. Notice that this time the macro has created a one-way table.
Frequency Counts
The log shows the generated TABLES statement.
Table 11.18 SAS Log
29   %counts(dsn=sasuser.all, cols=paid)
MPRINT(COUNTS):   title "Frequency Counts for SASUSER.ALL data set";
MPRINT(COUNTS):   proc freq data=sasuser.all;
MPRINT(COUNTS):   tables paid;
MPRINT(COUNTS):   run;

NOTE: There were 18 observations read from the data set SASUSER.SCHEDULE.
      WHERE Course_Code in ('C001', 'C002', 'C003', 'C004', 'C005', 'C006'),
NOTE: There were 207 observations read from the data set SASUSER.STUDENTS.
NOTE: There were 434 observations read from the data set SASUSER.REGISTER.
NOTE: There were 6 observations read from the data set SASUSER.COURSES.
NOTE: There were 434 observations read from the data set SASUSER.ALL.
NOTE: PROCEDURE FREQ used (Total process time):

Case Sensitivity in Macro Comparisons

Remember that comparisons that are made in %IF expressions are case sensitive.

Example

If you construct your %IF statement using incorrect case in any program text, the statement is never true. For example, the %IF statement below is always false because _null_ is specified in lowercase but is always stored in SAS in uppercase:
%macro prtlast;
   %if &syslast=_null_ %then %do;
      %put No data sets created yet.;
   %end;
   %else %do;
      proc print;
         title "Last Created Data Set is &syslast";
      run;
   %end;
%mend;
options mprint mlogic symbolgen;
%prtlast
Suppose SYSLAST has a value of _NULL_ when you submit this example. The following messages are written to the SAS log.
Table 11.19 SAS Log
29   %prtlast
MLOGIC(PRTLAST): Beginning execution.
SYMBOLGEN: Macro variable SYSLAST resolves to _NULL_
MLOGIC(PRTLAST): %IF condition &syslast = _null_ is FALSE

NOTE: The SAS System stopped processing this step because of errors.
NOTE: PROCEDURE PRINT used:
      real time           1:32.58
      cpu time            0.05 seconds

MPRINT(PRTLAST): proc print;
ERROR: There is not a default input data set (_LAST_ is _NULL_).
SYMBOLGEN: Macro variable SYSLAST resolves to _NULL_
MPRINT(PRTLAST): title "Last Created Data Set is _NULL_";
MPRINT(PRTLAST): run;

NOTE: The SAS System stopped processing this step because of errors.
NOTE: PROCEDURE PRINT used:
      real time           0.01 seconds
      cpu time            0.01 seconds
MLOGIC(PRTLAST): Ending execution.
Tip
The %UPCASE function is often useful when you construct %IF statements. For more information about the %UPCASE function, see Introducing Macro Variables.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.65.65