Transforming SAS® code into a SAS Macro using PERL

Document Sample
Transforming SAS® code into a SAS Macro using PERL Powered By Docstoc
					                Transforming SAS® code into a SAS Macro using PERL
                         Sumner H. Williams, CareOregon, Portland, OR, USA

ABSTRACT
SAS code is strengthened by transforming the code into a macro. This paper is intended to demonstrate using the
SAS Macro language to schedule macros to run at specific times during the day, week, month, quarter, or year.
Scheduling SAS Macros to run during off-peak hours greatly increases the hours that SAS is used by programmers.
By running a SAS program during normal work hours, a SAS license is being used and can not run anything else
AND you are using up computer cycles that could be spent in other ways. For periodic reports, this can be an
inefficient use of computer power. An efficient programmer would schedule each of those tasks to run during off
hours, but once the programmer has more than 10 scheduled tasks, the administration becomes tedius. This paper
will show how to decrease the administrative tedium of scheduling SAS Macros. Since this paper is about increasing
efficiency, the paper will also demonstrate using a PERL program which develops and sets up the scheduling macro.
Finally, one more PERL program will be demonstrated that transforms standard SAS code into SAS Macro code. In
the end, you will have a scheduling macro which makes calls to other macros depending on the date. The macros
that are called by the scheduling macro may have already been generated or may have been generated by PERL.
Keywords: PERL, SAS code, SAS Macro, goto.


INTRODUCTION
A programmer could schedule a task to run weekly, monthly, daily, quarterly, annually, etc. It is very easy to schedule
one macro that then runs all of the other macros. It would look like
%macro scheduled_reports;
%macro weekly_reports;
        /*&rogue_run was put in to force a report*/
        /*This will run on Sunday or if a rogue_run is requested
        %if %sysfunc(weekday("&SYSDATE"d)) = 1 or
        %sysfunc(index(&rogue_run,weekly)) > 0
        %then %do;
                 %put Running weekly reports;
                 proc printto new log= "&outdir\Weekly_&SYSDATE..log";
                 run;
                 %Weekly();
                 proc printto log=log;
                 run;
        %end;
%mend weekly_reports;
%weekly_reports;
%macro monthly_reports;
/*This should only occur monthly*/
        %if %sysfunc(day("&SYSDATE"d)) = 05 or
        %sysfunc(index(&rogue_run,monthly)) > 0
        %then %do;
                 proc printto new log= "&outdir\Monthly_&SYSDATE..log";
                 run;
                 %Monthly();
                 proc printto log=log;
                 run;
        %end;
%mend monthly_reports;
%monthly_reports;
%mend scheduled_reports;

The scheduled_reports macro can then be scheduled to run everyday during off hours. I have fulfilled the first


                                                          1
requirement in the abstract, namely how do I schedule macros to run with a macro. The thrust of using a single
macro to schedule numerous other macros is increasing efficiency of the computer and the analysts.
A SAS programmer might have several programs that could be turned into macros, but not enough time to make
the transformation. For code with no parameters, I have developed PERL programs that make the transformation.
For code that will need parameters, less effort will have to be spent making the transformation. For extant macros,
the PERL code can be used to add callable documentation.
First, there needs to be some background on my macro development. CareOregon’s macros all reside on a server
that I can not access. One problem with this is that I can not see the source code or documentation and that makes
it so I have to either remember how to use every macro I write OR I have to maintain two copies which may or may
not be synchronized. My solution is to document the macro in a peculiar way.


DOCUMENTING A SAS MACRO
The %example macro will demonstrate how I call for help when I forget how to use the macro.

    %macro %example(help); ‚
    %if &help = ? | %upcase(&help) = HELP %then %do; ƒ
      %put ERROR: Help was requested.; „
      %put %example_usage; …
      %goto exit; †
    %end;


      SAS Code goes here
    %exit: ‡
    %mend example;

It is best to give several options for calling help. ‚ is a positional, optional parameter. In this case, it is used to
indicate if help will be called. The user is allowed to give a “?” or some case independent version of “help.” ƒ
tests for whether help was called. A programmer might wish to add in other required macro variables to this list. „
is some helpful text that will be printed to the log. The programmer can and should modify this to satisfy the end
user. “ERROR:” will force the macro to bring up the log window when the user exits. … calls a second macro that
is the first macros name with “_usage” appended. … uses a %goto statement to assign a macro variable telling
SAS where to go next. goto statments were popular in FORTRAN, but are not generally recommended in typical
programming. Thsi is one case where a goto is acceptable since it determines the end of the program. A line
containing %exit: states where the code should goto. In this case the %exit: is added at the end of the macro.
In addition, PERL scripts write this section of the code. This keeps the coding consistent up to a point. Every macro
generated by PERL scripts has “help” as it’s first positional parameter. They all have goto statements. Within the
%if statement, they all have a call to the documentation macro. The documentation macro is generated using a
programmer supplied text file and PERL. If the code already is a macro, PERL will skip over those sections and only
generate the positional help parameter and subsequent logic if necessary.

EXTRA MACRO CODING
A second macro needs to be generated and it contains the documentation. The usage macro should include the
programmer(s), dates of modification, purpose of the code, the manner in which it can be used, the variables, and
the important output. Any additional requirements of the company should also be added, i.e. project identifiers,
requestors, or other important information. When PERL is used to create the utilization macro, the columns line up
and every line ends at the same point.




                                                          2
%macro example_usage;
%put ********************************************************************************;
%put *    Programmer:       Sumner Williams                                         *;
%put *    Modified:         Created (6/5/2008)                                      *;
%put *                      Macrotized (6/10/2008)                                  *;
%put *                      Added callable documentation                            *;
%put *    Purpose:          Demonstrate creation of SAS Macro with documentation    *;
%put *    Usage:            %nrbquote(%)example(help)                               *;
%put *    Variables:        help - option positional parameter.                     *;
%put ********************************************************************************;
%mend example_usage;


IMPLEMENTATION
First, the user needs to have PERL on their system. For Windows, this can be obtained from http://www.activestate.com/activeperl/.
For Linux/Mac, it should already be installed on your system. Second, the user needs to get the PERL scripts from
the author by emailing williamsu@careoregon.org or finding a friend that already has them. There are 4 subroutines
in the PERL program:
BuildAutomation{"<directory>\\Scheduling.sas");
OpenHeader("<directory\\file>");
ModifyHeaderfromFile("MacroDocumentation.txt");
CreateHeader("<directory>",
             "<directory>\\Temp.sas",
             "<macroname>");
BuildSASMacro("<directory>\\Temp.sas",
              "<directory>\\FinTest.sas",
              "<macroname>");
InsertMacro("<directory>\\Scheduling.sas",
            "weekly",
            "<macroname>",
            "<directory>\\<macroname>_&SYSDATE..log"
           );

Note that PERL thinks of a “\” as an escape character and so on windows, use two ”\\”. On Linux, the file system
uses “/” to distinguish file hierarchies, making a single “\” appropriate.
BuildAutomation
This generates the code for the scheduling macro. In the above example the code will be named Scheduling.sas.
It contains the code which will allow for a macro to be inserted in daily, weekly, monthly, etc. runs.
OpenHeader
This will open the header part of the SAS program (which can be a Macro). OpenHeader will look at all lines up
until it finds a line known to start a SAS program, i.e. a data step, options statement, sql statement, etc. Within
the header, the tags are appended with a colon (:). The above SAS example has tags for programmer, Modified,
Purpose, Usage, and Variables. If the program follows the guidelines I give, then the header will be read in fine.
Some tweaks will need to be made for other headers.
ModifyHeaderfromFile
Originally, the user was allowed to do this from the command line, but poor typing skills and impatience lead to
having the subroutine read a file. The file should only contain the updates to the documentation. Do not re-run the
same documentation file for each iteration of the SAS code as this would give you something like PROGRAMMER:
Sumner Williams Sumner Williams Sum...
CreateHeader
CreateHeader is fairly uninteresting because it takes the output from OpenHeader and ModifyHeaderfromFile and
puts it into a temporary file. While uninteresting, it is essential.


                                                         3
BuildSASMacro
BuildSASMacro reads the temporary file created by CreateHeader. It checks to make sure the program has help as
the first positional parameter of the macro. It will name the macro if necessary. It adds in the error checking code. It
adds in the %goto and the subsequent variable at the end of the program so that the program will exit when help is
requested. If the programmer has nested macros within macros, it will NOT create help code for the nested macros.
(This could be future work, time/desire permitting).
InsertMacro
This inserts the code to call the macro specified into the Scheduling.sas macro. It will not check to make certain
that you have not already put the code into the scheduling macro.

LIMITATIONS
One limitation is that it does not create help for nested or even serialized macros. SAS code on a separate server
can not be called unless the macro name is exactly the same as the file name ?. If three macros are in the
same program macrocode.sas, only the macro named macrocode will be able to be called by a SAS user not
on the server. Should the programmer need help with the PERL code, they can call BuildSASMacro(?) and the
documentation will be supplied in the console.
The PERL code also does not generate macro variables or force documentation of macro variables. It is astound-
ingly difficult to consider all of the ways in which a macro variable can be created. Input file names, data set names,
output file names, date values, can all be a macro variable. Therefore, to avoid over parameterizing a macro, none
of this has been added to the PERL scripts. Again, time/desire permitting, it may become a project.


RESULTS
Code will transform FROM:
data Example;

           infile "C:\Testing Folder\Example.csv" dsd;
           input claim \$ paid;
run;

proc sort data=Example;
        by claim;
run;

TO:
%macro Example_usage;
%put *********************************************************************;
%put *    PROGRAMMER:       Sumner Williams                              *;
%put *    MODIFIED:         20090504 Created                             *;
%put *    TRACK-IT:         0                                            *;
%put *    PURPOSE:          This is a demonstration program of the PERL *;
%put *                      programs.                                    *;
%put *    USAGE:            %nrbquote(%)Example%str()                                                              *;
%put *    REQUESTNUMBER:    123456789-pi                                 *;
%put *********************************************************************;
%mend Example_usage;
%macro Example_(help);
%if &help = ? | %upcase(&help) = HELP %then %do;
     %put ERROR:;
     %put Help has been requested.;
     %put Get help directly by running %nrbquote(%)Example_usage;
     %put Check the log for the help
     %Example_usage;
     %goto autoexit;


                                                          4
%end;

data Example;

           infile "C:\Testing Folder\Example.csv" dsd;
           input claim \$ paid;
run;

proc sort data=Example;
        by claim;
run;
%autoexit:
%mend Example;


CONCLUSION
This paper discussed how to schedule a macro using another macro. Efficiency is gained by having a second set
of programs built in PERL, construct the scheduling macro, the log file paths, insert the macros that are to-be-
scheduled, and finally, to have PERL build those macros where necessary. A few new ideas include the “callable”
documentation as well as adding in a help section to a macro. While this would not be of much us to the original
programmer that has access to the source code, it can be tremendously valuable to the end-user that has neither
access to the source code nor the memories of writing the macro.


ACKNOWLEDGMENTS
Ron Fehd “Macro Maven” has been helpful in his lectures and emails.


CONTACT INFORMATION
Contact the author:
Author:                        Sumner Williams
Company:                       CareOregon, Inc.
Address:                       315 SW 5th Ave. Suite 900
                               Portland, OR 97204
Phone:                         (503)416-5710
email:                         williamsu@careoregon.org

SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS
Institute Inc. in the USA and other countries. ® indicates USA registration.
Other brand and product names are trademarks of their respective companies.




                                                       5