Chapter 13 A Stepwise Method for Writing Macro Programs

Introduction

Building a Macro Program in Four Steps

Applying the Four Steps to an Example

Step 1: Write, test, and debug the SAS program(s) that you want the macro program to build

Step 2: Remove hard-coded programming constants from the program(s) in Step 1 and replace these constants with macro variables

Step 3: Create macro program(s) from the program(s) in Step 2

Step 4: Refine and generalize the macro program(s) in Step 3 by adding macro language statements like %IF-%THEN and %DO groups

Executing the REPORT Macro Program

Enhancing the Macro Program REPORT

 

Introduction

By now you’ve probably thought of at least one application that you could rewrite as a macro program. You've written the DATA steps and the PROC steps and you'd like to reuse this code. You've noticed ways that it can be generalized into a macro program.

After you decide that an application is appropriate to write as a macro program, build your macro program in steps. Developing your macro program in steps of increasing complexity ensures that your macro program ends up doing exactly what you want it to do. It is also easier to debug a macro program as you develop it.

This chapter describes the steps in taking SAS programming requests and writing a macro program to handle the requests. An example illustrates the process.

Building a Macro Program in Four Steps

The four basic steps in building a macro program are

Step 1. Write, test, and debug the SAS program(s) that you want the macro program to build. Do not use any macro variables or macro language statements in this step.

Step 2. Remove hard-coded programming constants from the program(s) in Step 1 and replace these constants with macro variables. Hard-coded programming constants are items like the values on a WHERE statement. Use %LET statements in open code to define the macro variables. Test and debug the program(s). Use the SYMBOLGEN option to verify the results of using the macro variables.

Step 3. Create macro program(s) from the program(s) in Step 2. Add parameters to the macro program(s) if appropriate. Most likely, it would be appropriate to make the macro variables that you define in Step 2 parameters to the macro program(s) that you write in this step. Use SAS options MPRINT and SYMBOLGEN to review the results of processing macro programs developed in this step.

Step 4. Refine and generalize the macro program(s) in Step 3 by adding macro language statements like %IF-%THEN and %DO groups. After you test several macro programs in Step 3, write programming statements to combine the macro programs into one macro program. Test the macro programming logic. Use the SAS options MPRINT, SYMBOLGEN, and MLOGIC to verify that your macro program works correctly.

 

Applying the Four Steps to an Example

Suppose that you have the ongoing task of producing sales reports for the computer books department of the bookstore using the year-to-date sales data set. These reports vary, but several items in the reports are the same and the layout of the reports is the same. To save yourself coding time each time a report is requested, you decide to develop a macro program that contains the framework of the reports. You customize the basic reports through the parameters that you specify to your macro program and the macro language statements contained within the program.

Your macro program should be able to perform the following tasks:

• Analyze any or all of the sales-related variables: COST, LISTPRICE, SALEPRICE, and PROFIT. Note that PROFIT is not saved in BOOKS.YTDALES and must be computed.

• Present these analyses for specific classifications. For example, the program should be able to compute overall sales; sales by section (variable SECTION); sales by publisher (variable PUBLISHER); sales by book format (variable BOOKFMT); sales by combinations of the classification variables.

• Present the analyses for a specific time period based on the date a book was sold (variable DATESOLD). Set the default time period of analysis to be the beginning of the year to the current date.

• Direct the results to an output destination other than the default HTML destination, and specify an ODS style when requesting this alternate destination.

Some of the reports that this macro program could produce include:

• Total of COST, LISTPRICE, SALEPRICE, and PROFIT for a specific time period.

• Total of SALEPRICE and PROFIT by section of the store for a specific time period.

• Bar charts of SALEPRICE and PROFIT by section of the store when the specific time period spans quarters or a year.

• Total PROFIT by section of the store and publisher of the books sold.

• Send any of these reports to a destination other than the default HTML destination, and optionally present the report in a specific ODS style.

The rest of this chapter applies the four steps to build a macro program that can perform the tasks listed above and generate the specific reports listed above and more. The application uses PROC TABULATE, PROC SQL, and PROC SGPLOT.

Step 1: Write, test, and debug the SAS program(s) that you want the macro program to build

The goal of the first step is to write a few sample programs that do not contain macro language code. This gives you the basic SAS coding framework that you can generalize later as you incorporate macro facility features.

Many different reports could be requested based on the preceding list. It would not be practical to write all possible programs. Instead, write a few representative sample programs that generally encompass the basic list of program requirements.

In this application, three sample programs are written to complete this step. The three are referred to as Report A, Report B, and Report C.

Report A presents overall totals for COST, LISTPRICE, SALEPRICE, and PROFIT for a specific time period, July 1, 2014-August 31, 2014.

Report B presents totals and bar charts by SECTION for SALEPRICE and PROFIT for the first quarter of 2014.

Report C presents totals by SECTION and PUBLISHER for COST and PROFIT for the year-to-date. Report C is sent to an RTF destination and the report is formatted in the STATISTICAL style that is distributed with SAS software and found in SASHELP.TMPLMST.

Program for Report A with No Macro Facility Features

Report A presents overall totals for COST, LISTPRICE, SALEPRICE, and PROFIT for July 1, 2014, through August 31, 2014.

*----REPORT A;

title “Sales Report”;

title2 “July 1, 2014 - August 31, 2014”;

data temp;

  set books.ytdsales(where=

                ('01jul2014'd le datesold le '31aug2014'd));

  profit=saleprice-cost;

  attrib profit label='Profit' format=dollar11.2;

run;

proc tabulate data=temp;

  var cost listprice saleprice profit;

  tables n*f=6.

         (cost listprice saleprice profit)*

          sum='Total'*f=dollar11.2;

  keylabel n='Titles Sold';

run;

Output 13.1 presents the report produced by the Report A program.

Output 13.1 Output from Step 1 Report A program

image

Program for Report B with No Macro Facility Features

Report B analyzes SALEPRICE and PROFIT for first quarter 2014. It presents a tabular report and two bar charts, one for each of the two analysis variables.

Each TITLE3 statement in the PROC SGPLOT steps displays two items that need to be determined before submitting the PROC SGPLOT steps. One item is the label of the analysis variable. The second item is the overall total of the analysis variable. The two SELECT statements in the PROC SQL step list these values. After executing the PROC SQL step, you insert the values into the TITLE3 statements. The output from PROC SQL is not shown.

*----REPORT B;

title “Sales Report”;

title2 “January 1, 2014 - March 31, 2014”;

data temp;

  set books.ytdsales(where=

                 ('01jan2014'd le datesold le '31mar2014'd));

  profit=saleprice-cost;

  attrib profit label='Profit' format=dollar11.2;

run;

proc sql;

  select name,label from dictionary.columns

    where libname='WORK' and memname='TEMP' and

          (upcase(name)='SALEPRICE' or upcase(name)='PROFIT'),

  select sum(saleprice) as saleprice_sum format=dollar11.2,

         sum(profit) as profit_sum format=dollar11.2

    from temp;

quit;

proc tabulate data=temp;

  class section;

  var saleprice profit;

  tables section all,

    n*f=6. (saleprice profit)*sum='Total'*f=dollar11.2;

  keylabel all='Total Sales'

           n='Titles Sold';

run;

proc sgplot data=temp;

  title3 “Total Sale Price for Time Period: $15,408.39”;

  hbar section / stat=sum response=saleprice datalabel;

  xaxis labelattrs=(weight=bold);

  yaxis label=' ' valueattrs=(weight=bold);

run;

proc sgplot data=temp;

  title3 “Total Profit for Time Period: $7,556.40”;

  hbar section / stat=sum response=profit datalabel;

  xaxis labelattrs=(weight=bold);

  yaxis label=' ' valueattrs=(weight=bold);

run;             ;

Output 13.2 presents the output produced by the Report B program.

Output 13.2 Output produced by the Step 1 Report B program

image

image

image

Program for Report C with No Macro Facility Features

Report C summarizes COST and PROFIT from the beginning of the year to the current date by section and publisher. Assume that the current date for the example is November 24, 2014. The program sends the report to the RTF destination and formats it with the STATISTICAL style found in SASUSER.TMPLMST. It does not send any output to the default HTML destination.

*----REPORT C;

ods html close;

ods rtf style=statistical;

title “Sales Report”;

title2 “January 1, 2014 - November 24, 2014”;

data temp;

  set books.ytdsales(where=

             ('01jan2014'd le datesold le '24nov2014'd));

  profit=saleprice-cost;

  attrib profit label='Profit' format=dollar11.2;

run;

proc tabulate data=temp;

  class section publisher;

  var cost profit;

  tables section*(publisher all) all,

    n*f=6. (cost profit)*sum*f=dollar11.2;

  keylabel all='Total Sales'

           n='Titles Sold';

run;

ods rtf close;

ods html;

Output 13.3 presents the output produced by the Report C program. Since the report is two pages long, Output 13.3 shows just the first and last sections and the grand total.

Output 13.3 Partial output produced by the Step 1 Report C program

image

After running these three programs and verifying that they display the information required, move on to Step 2.

Step 2: Remove hard-coded programming constants from the program(s) in Step 1 and replace these constants with macro variables

When you review the three programs created in Step 1, some patterns emerge:

• Observations are selected within a certain range of dates. This range is specified in the WHERE clause in the DATA step and in the titles.

• Analysis variables are selected from a defined set of variables.

• Classification variables are selected from a defined set of variables.

The values in the preceding list are hard-coded programming constants in the three programs from Step 1. Macro variables can be created in open code to hold these values.

Program for Report A with Step 2 Modifications

A revised Report A program follows that includes open code macro language statements. The %LET statements and macro variable references are in bold. The macro values TITLESTART and TITLESTOP are assigned the formatted values of the reporting period.

*----REPORT A;

%let repyear=2014;

%let start=01jul&repyear;

%let stop=31aug&repyear;

%let vars=cost listprice saleprice profit;

%let titlestart=%sysfunc(putn(“&start”d,worddate.));

%let titlestop=%sysfunc(putn(“&stop”d,worddate.));

options symbolgen;

title “Sales Report”;

title2 “&titlestart - &titlestop”;

data temp;

  set books.ytdsales(where=

      (“&start”d le datesold le “&stop”d));

  profit=saleprice-cost;

  attrib profit label='Profit' format=dollar10.2;

run;

proc tabulate data=temp;

  var &vars;

  tables n*f=6.

         (&vars)*

          sum='Total'*f=dollar11.2;

  keylabel n='Titles Sold';

run;

Program for Report B with Step 2 Modifications

Report B is modified to define macro variables in open code. Some of the changes that were made to this program were made to the Report A program.

The TITLE3 statements in the PROC SGPLOT steps in this version of Report B do not have to be manually edited with information produced by the PROC SQL step. In this version of Report B, PROC SQL saves the results it generates in macro variables. The TITLE3 statements reference the macro variables that the PROC SQL step creates.

The %SCAN function selects the name of each of the two analysis variables. The suffixes _SUM and _LABEL are concatenated to the analysis variable’s name, and these concatenated text strings specify the names of the macro variables that the SELECT statements creates.

The TITLE3 statements repeat the %SCAN function calls, and two ampersands precede these function calls. The text strings _SUM and _LABEL follow the %SCAN function calls. The two ampersands are required so that the macro processor scans the reference twice. Recall the discussion of resolving multiple ampersands at the end of Chapter 3. On the first pass, the macro processor resolves the two ampersands into one and the %SCAN function finds the analysis variable name. On the second pass, the macro processor sees a single ampersand followed by the name of the macro variable. The macro processor is able to resolve the macro variable reference. 

All of Report B has to be submitted only once to produce the output.

*----Report B;

%let repyear=2014;

%let start=01jan&repyear;

%let stop=31mar&repyear;

%let classvar=section;

%let vars=saleprice profit;

%let titlestart=%sysfunc(putn(“&start”d,worddate.));

%let titlestop=%sysfunc(putn(“&stop”d,worddate.));

options symbolgen;

title “Sales Report”;

title2 “&titlestart - &titlestop”;

data temp;

  set books.ytdsales(where=

      (“&start”d le datesold le “&stop”d));

  profit=saleprice-cost;

  attrib profit label='Profit' format=dollar11.2;

run;

proc sql noprint;

  select sum(%scan(&vars,1)) format=dollar11.2

         into :%scan(&vars,1)_sum

    from temp;

  select label into :%scan(&vars,1)_label trimmed

    from dictionary.columns

    where libname='WORK' and memname='TEMP' and

          upcase(name)=“%upcase(%scan(&vars,1))”;

  select sum(%scan(&vars,2)) format=dollar11.2

         into :%scan(&vars,2)_sum

    from temp;

  select label into :%scan(&vars,2)_label trimmed

    from dictionary.columns

    where libname='WORK' and memname='TEMP' and

          upcase(name)=“%upcase(%scan(&vars,2))”;

quit;

proc tabulate data=temp;

  class &classvar;

  var &vars;

  tables section all,

    n*f=6. (&vars)*sum='Total'*f=dollar11.2;

  keylabel all='Total Sales'

           n='Titles Sold';

run;

proc sgplot data=temp;

  title3

“Total &&%scan(&vars,1)_ label for Time Period: &&%scan(&vars,1)_sum”;

  hbar &classvar / stat=sum response=%scan(&vars,1) datalabel;

  xaxis labelattrs=(weight=bold);

  yaxis label=' ' valueattrs=(weight=bold);

run;

proc sgplot data=temp;

  title3

“Total &&%scan(&vars,2)_label for Time Period: &&%scan(&vars,2)_sum”;

  hbar &classvar / stat=sum response=%scan(&vars,1) datalabel;

  xaxis labelattrs=(weight=bold);

  yaxis label=' ' valueattrs=(weight=bold);

run;;

Program for Report C with Step 2 Modifications

The program for Report C is modified with the creation of macro variables in open code. The features added to this program are similar to and include some of those added to the programs for Report A and Report B.

*----REPORT C;

%let repyear=2014;

%let start=01jan&repyear;

%let stop=&sysdate9;

%let classvar=section publisher;

%let vars=cost profit;

%let titlestart=%sysfunc(putn(“&start”d,worddate.));

%let titlestop=%sysfunc(putn(“&stop”d,worddate.));

%let outputdest=rtf;

%let outputstyle=statistical;

options symbolgen;

ods html close;

ods &outputdest style=&outputstyle;

title “Sales Report”;

title2 “&titlestart - &titlestop”;

data temp;

  set books.ytdsales(where=

      (“&start”d le datesold le “&stop”d));

  profit=saleprice-cost;

  attrib profit label='Profit' format=dollar11.2;

run;

proc tabulate data=temp;

  class &classvar;

  var &vars;

  tables %scan(&classvar,1)*(%scan(&classvar,2) all) all,

    n*f=6. (&vars)*sum*f=dollar11.2;

  keylabel all='Total Sales'

           n='Titles Sold';

run;

ods &outputdest close;

ods html;

Step 3: Create macro program(s) from the program(s) in Step 2

In Step 2, similar changes were made to each of the three programs:

• Macro variables were defined for the range in dates that were selected from the data set.

• Macro variables were defined to hold the classification variables and analysis variables.

It might be tempting to jump into writing %DO blocks and conditional processing statements, but complete Step 3 first. In Step 3, define macro programs that use parameters. The parameters to the macro programs will usually be the macro variables that you define in Step 2. By not including macro language statements in these macro program definitions, you'll be sure that the parameters you define execute correctly.

Use the SYMBOLGEN and MPRINT options to verify that your programming changes do what you intend.

Program for Report A with Step 3 Modifications

The program for Report A is converted to a macro program. It has four keyword parameters, the same as the first four macro variables defined in open code in Step 2. The macro program assigns default values to three parameters: the start date, the stop date, and the analysis variables. The DATA and PROC steps in this program are the same as those in the Report A program in Step 2.

*----REPORT A;

options symbolgen mprint;

%macro reporta(repyear=,start=01JAN,stop=31DEC,

               vars=cost listprice saleprice profit);

  %let start=&start&repyear;

  %let stop=&stop&repyear;

  %let titlestart=%sysfunc(putn(“&start”d,worddate.));

  %let titlestop=%sysfunc(putn(“&stop”d,worddate.));

  title “Sales Report”;

  title2 “&titlestart - &titlestop”;

  data temp;

    set books.ytdsales(where=

        (“&start”d le datesold le “&stop”d));

    profit=saleprice-cost;

    attrib profit label='Profit' format=dollar10.2;

  run;

  proc tabulate data=temp;

    var &vars;

    tables n*f=6.

           (&vars)*

            sum='Total'*f=dollar11.2;

    keylabel n='Titles Sold';

  run;

%mend reporta;

The code to call REPORTA becomes

%reporta(repyear=2014,start=01jul,stop=31aug)

The start and stop dates for the reporting period are different than the default dates of January 1 and December 31. Therefore, you need to specify these two parameters. The analysis variables are the same as the default set of variables that are listed in the macro program definition for REPORTA. Therefore, the call to macro program REPORTA does not have to include the VARS parameter.

Program for Report B with Step 3 Modifications

The program for Report B in Step 2 is converted into the following macro program. This macro program defines five keyword parameters. Two parameters, the start date and the stop date, are defined with default values. The DATA and PROC steps in this program are the same as those in the Step 2 Report B program. The goal, however, will be to produce bar charts only when the values specified for START= and STOP= correspond to quarter start and end dates.

options symbolgen mprint;

%macro reportb(repyear=,start=01JAN,stop=31DEC,

               classvar=,vars=);

  %let start=&start&repyear;

  %let stop=&stop&repyear;

  %let titlestart=%sysfunc(putn(“&start”d,worddate.));

  %let titlestop=%sysfunc(putn(“&stop”d,worddate.));

  title “Sales Report”;

  title2 “&titlestart - &titlestop”;

  data temp;

    set books.ytdsales(where=

        (“&start”d le datesold le “&stop”d));

    profit=saleprice-cost;

    attrib profit label='Profit' format=dollar11.2;

  run;

proc sql noprint;

    select sum(%scan(&vars,1)) format=dollar11.2

           into :%scan(&vars,1)_sum

      from temp;

    select label into :%scan(&vars,1)_label trimmed

      from dictionary.columns

      where libname='WORK' and memname='TEMP' and

            upcase(name)=“%upcase(%scan(&vars,1))”;

    select sum(%scan(&vars,2)) format=dollar11.2

           into :%scan(&vars,2)_sum

      from temp;

    select label into :%scan(&vars,2)_label trimmed

      from dictionary.columns

      where libname='WORK' and memname='TEMP' and

            upcase(name)=“%upcase(%scan(&vars,2))”;

  quit;

  proc tabulate data=temp;

    class &classvar;

    var &vars;

    tables section all,

      n*f=6. (&vars)*sum='Total'*f=dollar11.2;

    keylabel all='Total Sales'

             n='Titles Sold';

  run;

  proc sgplot data=temp;

    title3

“Total &&%scan(&vars,1)_label for Time Period: &&%scan(&vars,1)_sum”;

    hbar &classvar / stat=sum response=%scan(&vars,1)

         datalabel;

    xaxis labelattrs=(weight=bold);

    yaxis label=' ' valueattrs=(weight=bold);

  run;

  proc sgplot data=temp;

    title3

“Total &&%scan(&vars,2)_label for Time Period: &&%scan(&vars,2)_sum”;

    hbar &classvar / stat=sum response=%scan(&vars,1)

         datalabel;

    xaxis labelattrs=(weight=bold);

    yaxis label=' ' valueattrs=(weight=bold);

  run;

%mend reportb;

The call to REPORTB is written as follows:

%reportb(repyear=2014,stop=31Mar,classvar=section,

         vars=saleprice profit)

The start date for the call to REPORTB is the same as the default value of January 1. Therefore, the start date does not have to be specified in the call to REPORTB. The stop date that is required to produce Report B is March 31. Since the default stop date is December 31, the value 31Mar must be specified as the stop date parameter value. The information in the report is summarized by the classification variable, SECTION. Two analysis variables are specified: SALEPRICE and PROFIT.

Program for Report C with Step 3 Modifications

Next, the program for Report C in Step 2 is converted into a macro program. This macro program defines seven keyword parameters. Two parameters, the start date and the stop date, are defined with default values. The DATA and PROC steps in this program are the same as those in the Report C program in Step 2.

This macro program differs from macro programs REPORTA and REPORTB because it adds two parameters that control the destination of the output. Macro programs REPORTA and REPORTB sent output to whatever the current destination in the SAS session was when they were called.

options symbolgen mprint;

%macro reportc(repyear=,start=01JAN,stop=31DEC,

               classvar=,vars=,

               outputdest=,style=);

  %let start=&start&repyear;

  %let stop=&stop&repyear;

  %let classvar=section;

  %let vars=saleprice profit;

  %let titlestart=%sysfunc(putn(“&start”d,worddate.));

  %let titlestop=%sysfunc(putn(“&stop”d,worddate.));

  %let outputdest=rtf;

  %let outputstyle=statistical;

  ods html close;

  ods &outputdest style=&outputstyle;

  title “Sales Report”;

  title2 “&titlestart - &titlestop”;

  data temp;

    set books.ytdsales(where=

        (“&start”d le datesold le “&stop”d));

    profit=saleprice-cost;

    attrib profit label='Profit' format=dollar11.2;

  run;

  proc tabulate data=temp;

    class section publisher;

    var cost profit;

    tables section*(publisher all) all,

      n*f=6. (cost profit)*sum*f=dollar11.2;

    keylabel all='Total Sales'

             n='Titles Sold';

  run;

  ods &outputdest close;

  ods html;

%mend reportc;

The call to REPORTC is specified as follows:

%reportc(repyear=2014,stop=24NOV,classvar=section publisher,

         vars=cost profit,outputdest=rtf,style=statistical)

The start date for the call to REPORTC is the default value of January 1. The stop date required to produce REPORTC is the current date of November 24 and must be specified since the default stop date is December 31. The information in the report is summarized by two classification variables, SECTION and PUBLISHER. Two analysis variables are specified, COST and PROFIT. The program directs the output to the RTF destination and formats the output in the STATISTICCAL style.

Step 4: Refine and generalize the macro program(s) in Step 3 by adding macro language statements like %IF-%THEN and %DO groups

The goal in Step 4 for the example application is to consolidate the three macro programs into one. The main similarity among the three programs is that they have most of the same parameters. Macro language statements are required to handle the following differences and to further generalize the programs:

• No classification variable is specified in Report A. One classification variable is specified in Report B. Two classification variables are specified in Report C.

• Report A uses all of the analysis variables. Reports B and C use some of the analysis variables.

• Report B is executed at the end of a quarter. Therefore, the third title is required for the bar charts.

• The number of PROC SGPLOT steps in Report B is equal to the number of analysis variables.

• Report C is sent to a destination other than the default HTML destination.

One enhancement that could be added to the macro program is to compute defaults for the report year and the stop date of the reports. Write the macro program so that when no report year is entered, use the current year. If stop date is specified as a null value, use the current date as the stop date for the report. If a default value has been specified for the stop date in the macro program definition, and the parameter is not included in the call to the program, the stop date will be the default value assigned to the parameter (31DEC).

The consolidated macro program incorporates conditional processing and iterative processing. One way to write this macro program follows. The statements in bold indicate where conditional and iterative processing occur as well as changes in parameter specifications.

A %IF statement checks if the time period spans one or more quarters or a year. If either condition is true, two iterative %DO loops execute. The output loop selects a classification variable from CLASSVARS. The inner loop selects an analysis variable from the VARS= parameter. Each iteration of the inner loop executes PROC SQL and PROC SGPLOT for the current value of CLASSVAR and VARNAME. Time period text is also added to the TITLE3 statement.

The parameters START= and STOP= in the Step 3 versions of the macro programs are renamed to STARTDDMMM= and STOPDDMMM in the following REPORT macro program definition.

Comments describe the processing of the macro program.

options mprint mlogic symbolgen;

%macro report(repyear=,startddmmm=01JAN,stopddmmm=31DEC,

              classvar=,vars=cost listprice saleprice profit,

              outputdest=html,style=) / minoperator;

  %*----Check if a value was specified for report year.

        If no value specified, use current year;

  %if &repyear= %then %let repyear=%substr(&sysdate9,6);

  %*----Check if stop date specified. If null, use

        current date as stop date;

  %if &stopddmmm= %then %let stopddmmm=%substr(&sysdate,1,5);

  %let startddmmm=%upcase(&startddmmm);

  %let stopddmmm=%upcase(&stopddmmm);

  %let start=&startddmmm&repyear;

  %let stop=&stopddmmm&repyear;

  %let titlestart=%sysfunc(putn(“&start”d,worddate.));

  %let titlestop=%sysfunc(putn(“&stop”d,worddate.));

  %*----Determine number of classification variables;

  %if &classvar ne %then

          %let nclassvars=%sysfunc(countw(&classvar));

  %else %let nclassvars=0;

  %*----Close default destination and open OUTPUTDEST;

  %*----Add STYLE if specified;

  ods html close;

  ods &outputdest

    %if &style ne %then %do;

      style=&style

    %end;

    ;

  title “Sales Report”;

  title2 “&titlestart - &titlestop”;

  data temp;

    set books.ytdsales(where=

       (“&start”d le datesold le “&stop”d));

    profit=saleprice-cost;

    attrib profit label='Profit' format=dollar10.2;

  run;

  proc tabulate data=temp;

    %*----Only submit a CLASS statement if there is a

         classification variable;

    %if &classvar ne %then %do;

       class &classvar;

    %end;

    var &vars;

    tables

      %if &classvar ne %then %do;

        %*---Determine leftmost row dimension variable;

        %scan(&classvar,1)

        %if &nclassvars ge 2 %then %do;

          %*----If more than one classification variable, nest

                remaining classification variables under the

                first.;

          %*----Use the substring function to extract

                classification variables after the first;

          %let pos2=%index(&classvar,%scan(&classvar,2));

          %*----Add the rest of the classification vars;

          * ( %substr(&classvar,&pos2) all)

        %end;

        all,

      %end;

      n*f=6. (&vars)*sum*f=dollar11.2;

      keylabel all='Total Sales'

               n='Titles Sold';

  run;

  %*----Check if date range is for quarter(s) or year;

  %if &startddmmm # 01JAN 01APR 01JUL 01OCT and

      &stopddmmm # 31MAR 30JUN 30SEP 31DEC and

      &startddmmm ne &stopddmmm %then %do;

    %*----Specific title text for Quarter(s) and for Year;

    %if &startddmmm=01JAN and &stopddmmm=31DEC

           %then %let timeperiod=Year;

    %else %let timeperiod=Quarter(s);

    %let nvars=%sysfunc(countw(&vars));

    %do c=1 %to &nclassvars;

      %let classvarname=%scan(&classvar,&c);

      %do v=1 %to &nvars;

        %let varname=%scan(&vars,&v);

        proc sql noprint;

          select sum(&varname) format=dollar11.2

                 into :&varname._sum

            from temp;

          select label into :&varname._label trimmed

            from dictionary.columns

            where libname='WORK' and memname='TEMP' and

                upcase(name)=“%upcase(&varname)”;

        quit;

        proc sgplot data=temp;

          title3

           “Total &&&varname._label for &timeperiod: &&&varname._sum”;

          hbar &classvarname / stat=sum response=&varname

                               datalabel;

          xaxis labelattrs=(weight=bold);

          yaxis label=' ' valueattrs=(weight=bold);

        run;

      %end;

    %end;

  %end;

  %*----Close report output. Open default destination;

  ods &outputdest close;

  ods html;

%mend report;

In Step 4, the SYMBOLGEN, MPRINT, and MLOGIC options can verify that your macro program works correctly. After you thoroughly check your macro program, turn these options off to save computing time.

Executing the REPORT Macro Program

Many types of reports can now be generated by the REPORT macro program, including Reports A, B, and C.

Obtaining the Contents of Report A Using the REPORT Macro Program

The first request to sum sales information for July and August 2014 is as follows:

%report(repyear=2014,start=01jul,stop=31aug)

The SAS log for the above submission of the call to %REPORT follows. The SAS code that macro program REPORT submits is in bold. Options MLOGIC and MPRINT are in effect.

The output produced by this call to macro program %REPORT is identical to that in Output 13.1.

4496  %report(repyear=2014,startddmmm=01jul,stopddmmm=31aug)

MLOGIC(REPORT):  Beginning execution.

MLOGIC(REPORT):  Parameter REPYEAR has value 2014

MLOGIC(REPORT):  Parameter STARTDDMMM has value 01jul

MLOGIC(REPORT):  Parameter STOPDDMMM has value 31aug

MLOGIC(REPORT):  Parameter CLASSVAR has value

MLOGIC(REPORT):  Parameter VARS has value cost listprice saleprice profit

MLOGIC(REPORT):  Parameter OUTPUTDEST has value html

MLOGIC(REPORT):  Parameter STYLE has value

SYMBOLGEN:  Macro variable REPYEAR resolves to 2014

MLOGIC(REPORT):  %IF condition &repyear= is FALSE

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31aug

MLOGIC(REPORT):  %IF condition &stopddmmm= is FALSE

MLOGIC(REPORT):  %LET (variable name is STARTDDMMM)

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01jul

MLOGIC(REPORT):  %LET (variable name is STOPDDMMM)

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31aug

MLOGIC(REPORT):  %LET (variable name is START)

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JUL

SYMBOLGEN:  Macro variable REPYEAR resolves to 2014

MLOGIC(REPORT):  %LET (variable name is STOP)

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31AUG

SYMBOLGEN:  Macro variable REPYEAR resolves to 2014

MLOGIC(REPORT):  %LET (variable name is TITLESTART)

SYMBOLGEN:  Macro variable START resolves to 01JUL2014

MLOGIC(REPORT):  %LET (variable name is TITLESTOP)

SYMBOLGEN:  Macro variable STOP resolves to 31AUG2014

SYMBOLGEN:  Macro variable CLASSVAR resolves to

MLOGIC(REPORT):  %IF condition &classvar ne is FALSE

MLOGIC(REPORT):  %LET (variable name is NCLASSVARS)

MPRINT(REPORT):   ods html close;

SYMBOLGEN:  Macro variable OUTPUTDEST resolves to html

SYMBOLGEN:  Macro variable STYLE resolves to

MLOGIC(REPORT):  %IF condition &style ne is FALSE

MPRINT(REPORT):   ods html ;

NOTE: Writing HTML Body file: sashtml47.htm

MPRINT(REPORT):   title “Sales Report”;

SYMBOLGEN:  Macro variable TITLESTART resolves to July 1, 2014

SYMBOLGEN:  Macro variable TITLESTOP resolves to August 31, 2014

MPRINT(REPORT):   title2 “July 1, 2014 - August 31, 2014”;

MPRINT(REPORT):   data temp;

SYMBOLGEN:  Macro variable START resolves to 01JUL2014

SYMBOLGEN:  Macro variable STOP resolves to 31AUG2014

MPRINT(REPORT):   set books.ytdsales(where= (“01JUL2014”d le datesold le “31AUG2014”d));

MPRINT(REPORT):   profit=saleprice-cost;

MPRINT(REPORT):   attrib profit label='Profit' format=dollar10.2;

MPRINT(REPORT):   run;

NOTE: There were 542 observations read from the data set BOOKS.YTDSALES.

      WHERE (datesold>='01JUL2014'D and datesold<='31AUG2014'D);

NOTE: The data set WORK.TEMP has 542 observations and 11 variables.

NOTE: DATA statement used (Total process time):

      real time           0.03 seconds

      cpu time            0.01 seconds

MPRINT(REPORT):   proc tabulate data=temp;

SYMBOLGEN:  Macro variable CLASSVAR resolves to

MLOGIC(REPORT):  %IF condition &classvar ne is FALSE

SYMBOLGEN:  Macro variable VARS resolves to cost listprice saleprice profit

MPRINT(REPORT):   var cost listprice saleprice profit;

SYMBOLGEN:  Macro variable CLASSVAR resolves to

MLOGIC(REPORT):  %IF condition &classvar ne is FALSE

SYMBOLGEN:  Macro variable VARS resolves to cost listprice saleprice profit

MPRINT(REPORT):   tables n*f=6. (cost listprice saleprice profit)*sum*f=dollar11.2;

MPRINT(REPORT):   keylabel all='Total Sales' n='Titles Sold';

MPRINT(REPORT):   run;

NOTE: There were 542 observations read from the data set WORK.TEMP.

NOTE: PROCEDURE TABULATE used (Total process time):

      real time           0.12 seconds

      cpu time            0.01 seconds

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JUL

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31AUG

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JUL

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31AUG

MLOGIC(REPORT):  %IF condition &startddmmm # 01JAN 01APR 01JUL 01OCT and       &stopddmmm #

      31MAR 30JUN 30SEP 31DEC and       &startddmmm ne &stopddmmm is FALSE

SYMBOLGEN:  Macro variable OUTPUTDEST resolves to html

MPRINT(REPORT):   ods html close;

MPRINT(REPORT):   ods html;

NOTE: Writing HTML Body file: sashtml48.htm

MLOGIC(REPORT):  Ending execution.

Obtaining the Contents of Report B Using the REPORT Macro Program

The second request to REPORT should generate statistics for sale price and profit by section for first quarter 2014. Since the reporting time period is a quarter, the macro program executes PROC SQL and PROC SGPLOT to produce bar charts.

%report(repyear=2014,stopddmmm=31Mar,classvar=section,

         vars=saleprice profit)

The SAS log for the above submission of the call to %REPORT follows. The SAS code that macro program REPORT submits is in bold. Options MLOGIC and MPRINT are in effect.

The output produced by this call to macro program %REPORT is identical to that in Output 13.2.

4613  %report(repyear=2014,stopddmmm=31Mar,classvar=section,

MLOGIC(REPORT):  Beginning execution.

4614           vars=saleprice profit)

MLOGIC(REPORT):  Parameter REPYEAR has value 2014

MLOGIC(REPORT):  Parameter STOPDDMMM has value 31Mar

MLOGIC(REPORT):  Parameter CLASSVAR has value section

MLOGIC(REPORT):  Parameter VARS has value saleprice profit

MLOGIC(REPORT):  Parameter STARTDDMMM has value 01JAN

MLOGIC(REPORT):  Parameter OUTPUTDEST has value html

MLOGIC(REPORT):  Parameter STYLE has value

SYMBOLGEN:  Macro variable REPYEAR resolves to 2014

MLOGIC(REPORT):  %IF condition &repyear= is FALSE

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31Mar

MLOGIC(REPORT):  %IF condition &stopddmmm= is FALSE

MLOGIC(REPORT):  %LET (variable name is STARTDDMMM)

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

MLOGIC(REPORT):  %LET (variable name is STOPDDMMM)

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31Mar

MLOGIC(REPORT):  %LET (variable name is START)

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

SYMBOLGEN:  Macro variable REPYEAR resolves to 2014

MLOGIC(REPORT):  %LET (variable name is STOP)

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31MAR

SYMBOLGEN:  Macro variable REPYEAR resolves to 2014

MLOGIC(REPORT):  %LET (variable name is TITLESTART)

SYMBOLGEN:  Macro variable START resolves to 01JAN2014

MLOGIC(REPORT):  %LET (variable name is TITLESTOP)

SYMBOLGEN:  Macro variable STOP resolves to 31MAR2014

SYMBOLGEN:  Macro variable CLASSVAR resolves to section

MLOGIC(REPORT):  %IF condition &classvar ne is TRUE

MLOGIC(REPORT):  %LET (variable name is NCLASSVARS)

SYMBOLGEN:  Macro variable CLASSVAR resolves to section

MPRINT(REPORT):   ods html close;

SYMBOLGEN:  Macro variable OUTPUTDEST resolves to html

SYMBOLGEN:  Macro variable STYLE resolves to

MLOGIC(REPORT):  %IF condition &style ne is FALSE

MPRINT(REPORT):   ods html ;

NOTE: Writing HTML Body file: sashtml51.htm

MPRINT(REPORT):   title “Sales Report”;

SYMBOLGEN:  Macro variable TITLESTART resolves to January 1, 2014

SYMBOLGEN:  Macro variable TITLESTOP resolves to March 31, 2014

MPRINT(REPORT):   title2 “January 1, 2014 - March 31, 2014”;

MPRINT(REPORT):   data temp;

SYMBOLGEN:  Macro variable START resolves to 01JAN2014

SYMBOLGEN:  Macro variable STOP resolves to 31MAR2014

MPRINT(REPORT):   set books.ytdsales(where= (“01JAN2014”d le datesold le “31MAR2014”d));

MPRINT(REPORT):   profit=saleprice-cost;

MPRINT(REPORT):   attrib profit label='Profit' format=dollar10.2;

MPRINT(REPORT):   run;

NOTE: There were 796 observations read from the data set BOOKS.YTDSALES.

      WHERE (datesold>='01JAN2014'D and datesold<='31MAR2014'D);

NOTE: The data set WORK.TEMP has 796 observations and 11 variables.

NOTE: DATA statement used (Total process time):

      real time           0.04 seconds

      cpu time            0.03 seconds

MPRINT(REPORT):   proc tabulate data=temp;

SYMBOLGEN:  Macro variable CLASSVAR resolves to section

MLOGIC(REPORT):  %IF condition &classvar ne is TRUE

SYMBOLGEN:  Macro variable CLASSVAR resolves to section

MPRINT(REPORT):   class section;

SYMBOLGEN:  Macro variable VARS resolves to saleprice profit

MPRINT(REPORT):   var saleprice profit;

SYMBOLGEN:  Macro variable CLASSVAR resolves to section

MLOGIC(REPORT):  %IF condition &classvar ne is TRUE

SYMBOLGEN:  Macro variable CLASSVAR resolves to section

SYMBOLGEN:  Macro variable NCLASSVARS resolves to 1

MLOGIC(REPORT):  %IF condition &nclassvars ge 2 is FALSE

SYMBOLGEN:  Macro variable VARS resolves to saleprice profit

MPRINT(REPORT):   tables section all, n*f=6. (saleprice profit)*sum*f=dollar11.2;

MPRINT(REPORT):   keylabel all='Total Sales' n='Titles Sold';

MPRINT(REPORT):   run;

NOTE: There were 796 observations read from the data set WORK.TEMP.

NOTE: PROCEDURE TABULATE used (Total process time):

      real time           0.15 seconds

      cpu time            0.03 seconds

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31MAR

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31MAR

MLOGIC(REPORT):  %IF condition &startddmmm # 01JAN 01APR 01JUL 01OCT and &stopddmmm # 31MAR 30JUN 30SEP 31DEC and &startddmmm ne &stopddmmm is TRUE

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 31MAR

MLOGIC(REPORT):  %IF condition &startddmmm=01JAN and &stopddmmm=31DEC is FALSE

MLOGIC(REPORT):  %LET (variable name is TIMEPERIOD)

MLOGIC(REPORT):  %LET (variable name is NVARS)

SYMBOLGEN:  Macro variable VARS resolves to saleprice profit

SYMBOLGEN:  Macro variable NCLASSVARS resolves to 1

MLOGIC(REPORT):  %DO loop beginning; index variable C; start value is 1; stop value is 1; by value is 1.

MLOGIC(REPORT):  %LET (variable name is CLASSVARNAME)

SYMBOLGEN:  Macro variable CLASSVAR resolves to section

SYMBOLGEN:  Macro variable C resolves to 1

SYMBOLGEN:  Macro variable NVARS resolves to 2

MLOGIC(REPORT):  %DO loop beginning; index variable V; start value is 1; stop value is 2; by value is 1.

MLOGIC(REPORT):  %LET (variable name is VARNAME)

SYMBOLGEN:  Macro variable VARS resolves to saleprice profit

SYMBOLGEN:  Macro variable V resolves to 1

MPRINT(REPORT):   proc sql noprint;

SYMBOLGEN:  Macro variable VARNAME resolves to saleprice

SYMBOLGEN:  Macro variable VARNAME resolves to saleprice

MPRINT(REPORT):   select sum(saleprice) format=dollar11.2 into :saleprice_sum from temp;

SYMBOLGEN:  Macro variable VARNAME resolves to saleprice

SYMBOLGEN:  Macro variable VARNAME resolves to saleprice

MPRINT(REPORT):   select label into :saleprice_label trimmed from dictionary.columns where libname='WORK' and memname='TEMP' and upcase(name)=“SALEPRICE”;

MPRINT(REPORT):   quit;

NOTE: PROCEDURE SQL used (Total process time):

      real time           0.00 seconds

      cpu time            0.00 seconds

MPRINT(REPORT):   proc sgplot data=temp;

SYMBOLGEN:  && resolves to &.

SYMBOLGEN:  Macro variable VARNAME resolves to saleprice

SYMBOLGEN:  Macro variable SALEPRICE_LABEL resolves to Sale Price

SYMBOLGEN:  Macro variable TIMEPERIOD resolves to Quarter(s)

SYMBOLGEN:  && resolves to &.

SYMBOLGEN:  Macro variable VARNAME resolves to saleprice

SYMBOLGEN:  Macro variable SALEPRICE_SUM resolves to  $22,854.27

MPRINT(REPORT):   title3 “Total Sale Price for Quarter(s):  $22,854.27”;

SYMBOLGEN:  Macro variable CLASSVARNAME resolves to section

SYMBOLGEN:  Macro variable VARNAME resolves to saleprice

MPRINT(REPORT):   hbar section / stat=sum response=saleprice datalabel;

MPRINT(REPORT):   xaxis labelattrs=(weight=bold);

MPRINT(REPORT):   yaxis label=' ' valueattrs=(weight=bold);

MPRINT(REPORT):   run;

NOTE: PROCEDURE SGPLOT used (Total process time):

      real time           0.90 seconds

      cpu time            0.12 seconds

NOTE: There were 796 observations read from the data set WORK.TEMP.

MLOGIC(REPORT):  %DO loop index variable V is now 2; loop will iterate again.

MLOGIC(REPORT):  %LET (variable name is VARNAME)

SYMBOLGEN:  Macro variable VARS resolves to saleprice profit

SYMBOLGEN:  Macro variable V resolves to 2

MPRINT(REPORT):   proc sql noprint;

SYMBOLGEN:  Macro variable VARNAME resolves to profit

SYMBOLGEN:  Macro variable VARNAME resolves to profit

MPRINT(REPORT):   select sum(profit) format=dollar11.2 into :profit_sum from temp;

SYMBOLGEN:  Macro variable VARNAME resolves to profit

SYMBOLGEN:  Macro variable VARNAME resolves to profit

MPRINT(REPORT):   select label into :profit_label trimmed from dictionary.columns where libname='WORK' and memname='TEMP' and upcase(name)=“PROFIT”;

MPRINT(REPORT):   quit;

NOTE: PROCEDURE SQL used (Total process time):

      real time           0.00 seconds

      cpu time            0.00 seconds

MPRINT(REPORT):   proc sgplot data=temp;

SYMBOLGEN:  && resolves to &.

SYMBOLGEN:  Macro variable VARNAME resolves to profit

SYMBOLGEN:  Macro variable PROFIT_LABEL resolves to Profit

SYMBOLGEN:  Macro variable TIMEPERIOD resolves to Quarter(s)

SYMBOLGEN:  && resolves to &.

SYMBOLGEN:  Macro variable VARNAME resolves to profit

SYMBOLGEN:  Macro variable PROFIT_SUM resolves to  $11,262.01

MPRINT(REPORT):   title3 “Total Profit for Quarter(s):  $11,262.01”;

SYMBOLGEN:  Macro variable CLASSVARNAME resolves to section

SYMBOLGEN:  Macro variable VARNAME resolves to profit

MPRINT(REPORT):   hbar section / stat=sum response=profit datalabel;

MPRINT(REPORT):   xaxis labelattrs=(weight=bold);

MPRINT(REPORT):   yaxis label=' ' valueattrs=(weight=bold);

MPRINT(REPORT):   run;

NOTE: PROCEDURE SGPLOT used (Total process time):

      real time           0.39 seconds

      cpu time            0.03 seconds

NOTE: There were 796 observations read from the data set WORK.TEMP.

MLOGIC(REPORT):  %DO loop index variable V is now 3; loop will not iterate again.

MLOGIC(REPORT):  %DO loop index variable C is now 2; loop will not iterate again.

SYMBOLGEN:  Macro variable OUTPUTDEST resolves to html

MPRINT(REPORT):   ods html close;

MPRINT(REPORT):   ods html;

NOTE: Writing HTML Body file: sashtml52.htm

MLOGIC(REPORT):  Ending execution.

Obtaining the Contents of Report C Using the REPORT Macro Program

The third report summarizes COST and PROFIT from the beginning of the current year through the current date. The analysis is classified by SECTION and PUBLISHER. Assume that the program was submitted on November 24, 2014. The program sends output to the RTF destination and formats the report using the STATISTICAL style. The third call to REPORT follows.

%report(stop=,

        classvar=section publisher, 

        vars=cost profit,

        outputdest=rtf,style=statistical)

The SAS log for the above submission of the call to %REPORT follows. The SAS code that macro program REPORT submits is in bold. Options MLOGIC and MPRINT are in effect.

The output produced by this call to macro program %REPORT is identical to that in Output 13.3.

4616  %report(stopddmmm=,

MLOGIC(REPORT):  Beginning execution.

4617          classvar=section publisher,

4618          vars=cost profit,

4619          outputdest=rtf,style=analysis)

MLOGIC(REPORT):  Parameter STOPDDMMM has value

MLOGIC(REPORT):  Parameter CLASSVAR has value section publisher

MLOGIC(REPORT):  Parameter VARS has value cost profit

MLOGIC(REPORT):  Parameter OUTPUTDEST has value rtf

MLOGIC(REPORT):  Parameter STYLE has value analysis

MLOGIC(REPORT):  Parameter REPYEAR has value

MLOGIC(REPORT):  Parameter STARTDDMMM has value 01JAN

SYMBOLGEN:  Macro variable REPYEAR resolves to

MLOGIC(REPORT):  %IF condition &repyear= is TRUE

MLOGIC(REPORT):  %LET (variable name is REPYEAR)

SYMBOLGEN:  Macro variable SYSDATE9 resolves to 24NOV2014

SYMBOLGEN:  Macro variable STOPDDMMM resolves to

MLOGIC(REPORT):  %IF condition &stopddmmm= is TRUE

MLOGIC(REPORT):  %LET (variable name is STOPDDMMM)

SYMBOLGEN:  Macro variable SYSDATE resolves to 24NOV2014MLOGIC(REPORT):  %LET (variable name is STARTDDMMM)

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

MLOGIC(REPORT):  %LET (variable name is STOPDDMMM)

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 24NOV

MLOGIC(REPORT):  %LET (variable name is START)

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

SYMBOLGEN:  Macro variable REPYEAR resolves to 2014

MLOGIC(REPORT):  %LET (variable name is STOP)

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 24NOV

SYMBOLGEN:  Macro variable REPYEAR resolves to 2014

MLOGIC(REPORT):  %LET (variable name is TITLESTART)

SYMBOLGEN:  Macro variable START resolves to 01JAN2014

MLOGIC(REPORT):  %LET (variable name is TITLESTOP)

SYMBOLGEN:  Macro variable STOP resolves to 24NOV2014

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

MLOGIC(REPORT):  %IF condition &classvar ne is TRUE

MLOGIC(REPORT):  %LET (variable name is NCLASSVARS)

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

MPRINT(REPORT):   ods html close;

SYMBOLGEN:  Macro variable OUTPUTDEST resolves to rtf

SYMBOLGEN:  Macro variable STYLE resolves to analysis

MLOGIC(REPORT):  %IF condition &style ne is TRUE

SYMBOLGEN:  Macro variable STYLE resolves to analysis

MPRINT(REPORT):   ods rtf style=analysis ;

NOTE: Writing RTF Body file: sasrtf.rtf

MPRINT(REPORT):   title “Sales Report”;

SYMBOLGEN:  Macro variable TITLESTART resolves to January 1, 2014

SYMBOLGEN:  Macro variable TITLESTOP resolves to November 24, 2014

MPRINT(REPORT):   title2 “January 1, 2014 - November 24, 2014”;

MPRINT(REPORT):   data temp;

SYMBOLGEN:  Macro variable START resolves to 01JAN2014

SYMBOLGEN:  Macro variable STOP resolves to 24NOV2014

MPRINT(REPORT):   set books.ytdsales(where= (“01JAN2014”d le datesold le “24NOV2014”d));

MPRINT(REPORT):   profit=saleprice-cost;

MPRINT(REPORT):   attrib profit label='Profit' format=dollar10.2;

MPRINT(REPORT):   run;

NOTE: There were 3007 observations read from the data set BOOKS.YTDSALES.

      WHERE (datesold>='01JAN2014'D and datesold<='24NOV2014'D);

NOTE: The data set WORK.TEMP has 3007 observations and 11 variables.

NOTE: DATA statement used (Total process time):

      real time           0.04 seconds

      cpu time            0.01 seconds

MPRINT(REPORT):   proc tabulate data=temp;

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

MLOGIC(REPORT):  %IF condition &classvar ne is TRUE

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

MPRINT(REPORT):   class section publisher;

SYMBOLGEN:  Macro variable VARS resolves to cost profit

MPRINT(REPORT):   var cost profit;

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

MLOGIC(REPORT):  %IF condition &classvar ne is TRUE

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

SYMBOLGEN:  Macro variable NCLASSVARS resolves to 2

MLOGIC(REPORT):  %IF condition &nclassvars ge 2 is TRUE

MLOGIC(REPORT):  %LET (variable name is POS2)

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

SYMBOLGEN:  Macro variable CLASSVAR resolves to section publisher

SYMBOLGEN:  Macro variable POS2 resolves to 9

SYMBOLGEN:  Macro variable VARS resolves to cost profit

MPRINT(REPORT):   tables section * (publisher all) all, n*f=6. (cost profit)*sum*f=dollar11.2;

MPRINT(REPORT):   keylabel all='Total Sales' n='Titles Sold';

MPRINT(REPORT):   run;

NOTE: There were 3007 observations read from the data set WORK.TEMP.

NOTE: PROCEDURE TABULATE used (Total process time):

      real time           0.14 seconds

      cpu time            0.03 seconds

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 24NOV

SYMBOLGEN:  Macro variable STARTDDMMM resolves to 01JAN

SYMBOLGEN:  Macro variable STOPDDMMM resolves to 24NOV

MLOGIC(REPORT):  %IF condition &startddmmm # 01JAN 01APR 01JUL 01OCT and &stopddmmm # 31MAR 30JUN 30SEP 31DEC and &startddmmm ne &stopddmmm is FALSE

SYMBOLGEN:  Macro variable OUTPUTDEST resolves to rtf

MPRINT(REPORT):   ods rtf close;

MPRINT(REPORT):   ods html;

NOTE: Writing HTML Body file: sashtml53.htm

MLOGIC(REPORT):  Ending execution.

Enhancing the Macro Program REPORT

Numerous enhancements can be added to a macro program after completing Step 4. A balance needs to be made, however, between generalizing a macro program and hard-coding features of a macro program. Each programming situation is different. For example, a macro program that you intend to use repeatedly for years might be worth your investment of time to enhance the macro program. A macro program that you might use only once or twice, and was developed mainly as a timesaver in writing SAS code, might not be worth enhancing.

Enhancements to consider adding to the macro program REPORT include the following:

• Make the data set name a parameter so that you can analyze other data sets.

• Check that the data set exists and that it contains observations.

• Add more error checking of the parameter values passed to the program. For example, you might want to check that the start date is after the stop date. You might also want to verify that the output destination parameter value is valid and that the style exists.

• Refine the layout of the PROC TABULATE report when there are more than two classification variables.

• Enhance the output produced by PROC SGPLOT output. Add parameters to further customize the output.

• Delete the temporary data set created by the macro program.

• Declare as local all the macro variables that REPORT creates.

..................Content has been hidden....................

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