Re: Possible to run a SAS program within another SAS program? #5

Subject: Re: Possible to run a SAS program within another SAS program?
Summary: Simple introduction to macro and design issues in the context
         of multiple programs producing data with a version indicator
Respondent: Ian Whitlock iw1junk@comcast.net


It looks like you are ready to think about program design with a little
macro.  As you present it, the keys ideas are

   1) set of multiply related programs
      sometimes run as a set and sometimes only a subset

   2) some programs produce data set with version indicator

Your basic set up indicates that you are thinking of each program as a unit
of code.  In this case it makes sense to wrap each program in a macro since
a macro is a parameterized package of code.  The advantage is that the
package has been separated from the file concept, so one file may contain
multiple packages or one package may have parts in multiple files.

   %macro prog1 ( dummy ) ;
      /* original program prog1.sas */
   %mend  prog1 ;

You now have the flexibility to either make the library an autocall library

   filename macs "c:\sasprogs" ;
   options mautosource sasautos = ( pgm sasautos ) ;
   /* code loaded automatically when needed */
   %prog1 ()
   %prog3 ()

or simply use %INCLUDE to compile the macros

   filename macs "c:\sasprogs" ;
   /* code explicitly loaded before use */
   %inc macs ( prog1 prog3 ) ;
   /* call programs */

There are advantages to explicitly including the macro code, and there are
advantages to letting the system handle it.  Much of the time it doesn't
matter.  The include is annoying when the system gets very big and complex
because the macros tend to get included more than necessary.  However,
the autocall is annoying when you plan to make changes since a macro is
compiled just once, and you can run into name conflicts as the size of the
system and number of autocall libraries grows.  Personally I like the to
keep general tools in an autocall library, with project code either in a
separate autocall library if used frequently or %included when used less

The parentheses in the macro statement and call indicate parameters for
that unit of code.  There are two types of parameters - key word parameters
for serious work, and positional parameters for those that wish to play
with macros.  (I started with the parameter DUMMY because version 6 broke
the capability of defining a macro with an empty list of parameters and it
didn't get fully fixed until rather recently.  So supplying a name, DUMMY,
guarantees compatibility across all versions.  I remove the dummy parameter
whenever I know what parameters should be present.  Note that used macros
always grow parameters.)  It is not unreasonable to treat version as a
parameter.  In fact that is what you have done because global macro
variables are essentially program parameters.  The big design issue is -
who should own the version parameter value?

With a %LET in the code that block of code owns the value and it must be
edited in order to change it.  Moving to a macro organization suggests that
it makes sense to have

    %macro prog1 ( version = ) ;
    %mend  prog1 ;

and the call

    %prog1 ( version = c )

In this case it is the controlling or driving program that owns the version
and gives the correct version to each part.  Now the editing takes place in
the driver.  The advantage is that the editing is in one place, and the
disadvantage is that you still have to worry about making the correct
version assignments.  The third possibility is to automate by letting the
data own the version concept, but this can mean that you might have
problems recreating older versions without deleting or moving newer

Let's keep your idea of program control but let the data know what version
is next.  It is somewhat easier with numbers, so I will look at data sets
W_001, W_002, etc.  Let's assign a macro to find the latest version number
and increment by 1.

   %macro getversion ( lib = work    /* default library              */
                     , memspec = W_  /* example - include underscore */
                     , retvar = version /* default variable name     */
                     ) ;
       %* assign &retvar next version number
          user responsible for declaring variable
       proc sql noprint ;
          select put(max(input(scan(memname,-1,"_"),3.))+1,z3.)
                    into : &retvar
            from dictionary.tables
            where libname = "%upcase(&lib)"
              and memname like "%upcase(&memspec)%"
       quit ;
   %mend  getversion ;

   /* test code for GETVERSION */
   %macro prog1 ( dummy ) ;
      %* make new dataset w_? *;
      %local version ;
      %getversion (lib = work , memspec = w )
      data t_&version ;
         x = 2 ;
      run ;
   %mend  prog1 ;

   options mprint ;
   data w_001 w_002 ; x = 1 ; run ;

You could have it both ways.  Assign the next available version number when
no version is specified and use the specified version when given.

   %macro prog1 ( memspec = w , version = ) ;
      %* make new dataset work.&memspec._? *;
      %if %length(&version) = 0 %then
      %do ;
         %getversion (lib = work , memspec = &memspec )
      %end ;
      data work.&memspec._&version ;
         x = 2 ;
      run ;
   %mend  prog1 ;

   /* test code for new prog1 */
   options mprint ;
   /* next available version */
   %prog1 ( memspec = w_ )
   /* overwrite first version */
   %prog1 ( memspec = w_ , version = 001 )

I put the %IF in PROG1, but it probably belongs in GETVERSION.  The
question here is, do you want to make PROG1 have this ability or do you
want to write it once so all users of GETVERSION have this ability?

The real question about data versions involves why there are versions in
the first place.  Do you change the version because the code changes?  Then
the code also should be saved in versions.  What sense does it make to know
I have B-data when I don't know what the B-code was.  Do you have versions
because you run each week?  Maybe a date indicator would be better.  Do you
simply need to back up to a previous version of data.  Some operating
systems give support for generations of data.  In fact I thought the
current SAS also provided this, but I couldn't locate it in the help files.
The older support that SAS supplied is the AGE statement in PROC DATASETS.

Personally I tend to keep the data minimal and put the emphasis on the
code.  For example,  I would rather rerun code to add variables each time
they are needed than manage two sets of data one with the variables and one
without.  Of course in any project there are tradeoffs between these two

Ian Whitlock
Date:         Wed, 7 Dec 2005 22:32:49 -0800
Reply-To:     oseithedude@GMAIL.COM
Sender:       "SAS(r) Discussion"
From:         oseithedude@GMAIL.COM
Organization: http://groups.google.com
Subject:      Re: Possible to run a SAS program within another SAS program?
Comments: To: sas-l
In-Reply-To:  <1133984548.701792.8300@z14g2000cwz.googlegroups.com>
Content-Type: text/plain; charset="iso-8859-1"
nevin.krishna@gmail.com wrote:
> You could use the %include statement to call a specified program.
> for example :
> %include "c:\documents and settings\nkrishna\my
> documents\macros\upcase_mac.sas";
> where upcase_mac.sas is a program stored in the above path..so you
> could write an include statement for each program and then copy and
> paste them into any order you need..unless of course i am
> misunderstanding your needs..:-)
> --nevin
Thanks for all the responses! I have another questions though... in 4
or 5 of the SAS programs, there is a simple macro statement that helps
indicate the version of the end dataset that is created. They all have
a %let version = A statement, for example, at the beginning of the
program... the macro variable is tacked on to the end of the dataset
name to let me know that this is version "A" of the dataset. Each time
I run the programs, I change the version letter within the programs
(e.g., to "B" or "C")... if I create a separate SAS program using
%include to run all of these programs, could I also set the version
macro variable to whatever letter I want within this same program or is
this not possible?
iw1junk (1187)
12/9/2005 12:09:42 AM
comp.soft-sys.sas 142828 articles. 3 followers. Post Follow

0 Replies

Similar Articles

[PageSpeed] 59