Some Generalities on Macros and Macro Variables ... 1. Macro variables are ordinarily alphanumeric strings. Thus if you define &num as %let num = 100 + 200 ; then the contents of &num are actually NOT 300; it will just be the character string '100 + 200' ; However, when the program executes, the value looks to the SAS interpreter the same as if you had written in 100 + 200, and it evaluates this expression correctly as equalling 300. 2. When macro variables or macro functions are used in titles, the titles must be given in double quotes: Doesn't work: title1 = 'Today is &sysdate' ; Does work : title1 = "Today is &sysdate" ; 3. The function SYMPUT: Ordinarily macro variables are created outside of SAS data steps. Their values are set in advance and do not depend on the data. There are occasions where you want to have available information from one data step that might be useful in a later data step. This is what the function SYMPUT accomplishes. See the program example "~john-c/5412/macexamp.sas". 4. When you include macros in your program, it is a good idea to add the MPRINT option on the 'options' line: options linesize = 100 MPRINT ; This causes a printout of the translated macro to be printed on the log file. This can be very useful for debugging a macro. 5. Note that unless you take some precautions, variables defined in a macro may have the same name as variables that you use elsewhere in your program. This can result in changing the data without intending to do so. You may not realize it has happened. This problem is especially bad when you are using a macro that someone else has developed, and you are making use of it in your program by the "%include" statement. You may not even know what variable names have been chosen previously. You can make variables "local" to the macro by using the %LOCAL command near the beginning of the macro: %LOCAL xtemp ytemp zmacvar wmacvar ; However, these will be *macro* variables. 6. Positional parameters vs. keyword parameters: Here is a macro which makes use of both positional and keyword parameters: ======================================================================= *Example of use of positional and keyword parameters ... ; options linesize = 80 MPRINT ; footnote "~john-c/5421/macros.sas &sysdate &systime" ; *----------------------------------------------------------------------; %macro mv(dataset, atitle, stats = n mean std, varbls = 1) ; proc means data = &dataset &stats ; var &varbls ; title "&atitle" ; %mend ; *----------------------------------------------------------------------; data xvals ; input age weight height FEV1 ; cards; 31 155 175 2.44 48 176 165 3.45 50 104 144 1.22 63 117 180 182 ; run ; %mv(xvals, Summary Stats: from Proc Means, stats = n sum var, varbls = age weight height FEV1) ; ======================================================================= The first two parameters to the macro, 'xvals' and 'title', are positional parameters. The last two, 'stats = ' and 'varbls = ' are keyword parameters. Note that: 1) The positional parameters always precede the keyword parameters 2) The keyword parameters have default values. If the macro is called with the keyword parameter fields left blank, as in %mv(xvals, Summary Stats: from Proc Means) ; then the default values are used. The following is the printout from the program above: ======================================================================== Summary Stats: from Proc Means 1 18:24 Monday, November 11, 2002 Variable N Sum Variance --------------------------------------- AGE 4 192.0000000 172.6666667 WEIGHT 4 552.0000000 1110.00 HEIGHT 4 664.0000000 254.0000000 FEV1 4 189.1100000 8067.57 --------------------------------------- ~john-c/5421/macros.sas 11NOV02 18:24 ======================================================================== Another macro example: a macro that finds the median in an array of numbers (array length, 20 or smaller; here only the median of the first 6 nonblank values is found): options linesize = 100 mprint ; * ====================================================================; %macro xmed(x, maxlen, xmedian) ; * --------------------------------------------------------------------; * ; * Sort the array in DESCENDING order: missing values occur last. ; * ; * --------------------------------------------------------------------; do i = 2 to &maxlen ; do j = 1 to i - 1 ; ti = &x(i) ; tj = &x(j) ; if ti eq . then ti = -99999 ; if tj eq . then tj = -99999 ; t = ti - tj ; if (t > 0) then do ; temp = &x(j) ; &x(j) = &x(i) ; &x(i) = temp ; end ; end ; end ; xlen = 0 ; do i = 1 to &maxlen ; a = &x(i) ; if a ne . then xlen = xlen + 1 ; end ; xmid = int(xlen / 2) ; if 2 * xmid eq xlen then do ; xmedian = .5 * (&x(xmid) + &x(xmid + 1)) ; end ; if 2 * xmid ne xlen then do ; &xmedian = &x(xmid + 1) ; end ; %mend ; *======================================================================; data xdata ; x1 = 12; x2 = 10; x3 = 2 ; x4 = 4; x5 = 1 ; x6 = 9 ; output ; x1 = .; x2 = 19; x3 = 4 ; x4 = 9; x5 = 8 ; x6 = . ; output ; x1 = 7; x2 = 9; x3 = . ; x4 = 1; x5 = 1 ; x6 = 0 ; output ; x1 = 27; x2 = 99; x3 = 0 ; x4 = 5; x5 = . ; x6 = . ; output ; x1 = 1; x2 = .; x3 = 3 ; x4 = 8; x5 = . ; x6 = 7 ; output ; run ; data xarrays ; set xdata ; array x(20) ; retain pass 1 ; file 'outmed.file' ; if pass eq 1 then do ; put ' Data Points and Medians: program ~john-c/median.sas' ; put " Date: &sysdate Time: &systime" ; put ' ' ; put ' ' ; end ; pass = pass + 1 ; x(1) = x1 ; x(2) = x2 ; x(3) = x3 ; x(4) = x4 ; x(5) = x5 ; x(6) = x6 ; %xmed(x, 20, xmedian) ; put @2 'X-Values: ' x1 x2 x3 x4 x5 x6 @30 ' Median: ' xmedian ; run ; options linesize = 100 mprint ; * ====================================================================; %macro xmed(x, maxlen, xmedian) ; * --------------------------------------------------------------------; * ; * Sort the array in DESCENDING order: missing values occur last. ; * ; * --------------------------------------------------------------------; do i = 2 to &maxlen ; do j = 1 to i - 1 ; ti = &x(i) ; tj = &x(j) ; if ti eq . then ti = -99999 ; if tj eq . then tj = -99999 ; t = ti - tj ; if (t > 0) then do ; temp = &x(j) ; &x(j) = &x(i) ; &x(i) = temp ; end ; end ; end ; xlen = 0 ; do i = 1 to &maxlen ; a = &x(i) ; if a ne . then xlen = xlen + 1 ; end ; xmid = int(xlen / 2) ; if 2 * xmid eq xlen then do ; xmedian = .5 * (&x(xmid) + &x(xmid + 1)) ; end ; if 2 * xmid ne xlen then do ; &xmedian = &x(xmid + 1) ; end ; %mend ; *======================================================================; data xdata ; x1 = 12; x2 = 10; x3 = 2 ; x4 = 4; x5 = 1 ; x6 = 9 ; output ; x1 = .; x2 = 19; x3 = 4 ; x4 = 9; x5 = 8 ; x6 = . ; output ; x1 = 7; x2 = 9; x3 = . ; x4 = 1; x5 = 1 ; x6 = 0 ; output ; x1 = 27; x2 = 99; x3 = 0 ; x4 = 5; x5 = . ; x6 = . ; output ; x1 = 1; x2 = .; x3 = 3 ; x4 = 8; x5 = . ; x6 = 7 ; output ; run ; data xarrays ; set xdata ; array x(20) ; retain pass 1 ; file 'outmed.file' ; if pass eq 1 then do ; put ' Data Points and Medians: program ~john-c/median.sas' ; put " Date: &sysdate Time: &systime" ; put ' ' ; put ' ' ; end ; pass = pass + 1 ; x(1) = x1 ; x(2) = x2 ; x(3) = x3 ; x(4) = x4 ; x(5) = x5 ; x(6) = x6 ; %xmed(x, 20, xmedian) ; put @2 'X-Values: ' x1 x2 x3 x4 x5 x6 @30 ' Median: ' xmedian ; run ; *======================================================================; Output from the program: *----------------------------------------------------------------------; Data Points and Medians: program ~john-c/median.sas Date: 10NOV02 Time: 14:06 X-Values: 12 10 9 4 2 1 Median: 6.5 X-Values: 19 9 8 4 . . Median: 8.5 X-Values: 9 7 1 1 0 . Median: 1 X-Values: 99 27 5 0 . . Median: 16 X-Values: 8 7 3 1 . . Median: 5 *======================================================================; PubH 5421 ~john-c/5421/notes.023a Last update: November 30, 2005.