What Are These
Macros are a block of code that can be executed/called on demand
Global variables are variables that you assign a value to, which can be referenced anywhere within your program. (Leah s definition) Think the proper name for them is: Global Macro Variables
Why Use Them
Macros: Allow for complex, robust, dynamic coding When you have code that is used repeatedly within a program itself or within a project One instance ensures you have the latest version of the code Keeps code neat and tidy
Macro Variables: Allows for more dynamic, iterative programming If a variable appears in various parts of your code, changing it in 1 place ensures all instances of it will be updated. Great for use in Reporting - Titles and Footnotes
Example of how I use macros: Very Basic: Reading in a series of flat files - write the code only once - execute as many times as needed
%MACRO FILEREAD; DATA T1(KEEP=VAR1 VAR2 VAR3); INFILE "/SAS_data/pathname/morepathname/&FLNAME..dat" LRECL=2916 MISSOVER PAD EOF=LAST; INPUT @1 var1 $1. @2 var2 1. @3 var3 $CHAR3.; %MEND FILEREAD; %LET FLNAME=y0708/y0708; %FILEREAD; %LET FLNAME=y0809/y0809; %FILEREAD;
Components of a Macro: Starts with: %macro macro_name; Ends with: %mend macro_name; Is invoked/called by: %macro_name;
%MACRO FILEREAD; DATA T1(KEEP=VAR1 VAR2 VAR3); INFILE "/SAS_data/pathname/morepathname/&FLNAME..dat" LRECL=2916 MISSOVER PAD EOF=LAST; INPUT @1 var1 $1. @2 var2 1. @3 var3 $CHAR3.; %MEND FILEREAD; %LET FLNAME=y0708/y0708; %FILEREAD; %LET FLNAME=y0809/y0809; %FILEREAD;
Global Macro Variable: %Let var_name = value Eg: %LET FLNAME=y0708/y0708; Referenced by: &var_name
Important to note: These value of the variable is exactly what you set it to be. Eg: %let x = A; %let x = A ; These variables are not kept in a dataset.
%MACRO FILEREAD; DATA T1(KEEP=VAR1 VAR2 VAR3); INFILE "/SAS_data/pathname/morepathname/&FLNAME..dat" LRECL=2916 MISSOVER PAD EOF=LAST; INPUT @1 var1 $1. @2 var2 1. @3 var3 $CHAR3.; %MEND FILEREAD; %LET FLNAME=y0708/y0708; %FILEREAD; %LET FLNAME=y0809/y0809; %FILEREAD;
/* GLOBAL VARIABLES */ %LET FROMDT=MDY(01,01,1985); /* FORMAT MONTH,DAY,YEAR */ %LET TODT=MDY(03,31,2008); /* FORMAT MONTH,DAY,YEAR */ %LET SLCTTYPE=3; /* 1=MALE, 2=FEMALE, 3=BOTH */ %LET DT4SLCTN='B'; /* A=ADMIT, D=DISCH, B=BOTH */ %LET CODEICD=25; /* 0-25 ARE VALID FOR 02-03 */ %LET CODEPROC=20; /* 0-20 ARE VALID FOR 02-03 */ %LET SLCTALL=0; /* 1=SELECT ALL RECS REGARDLESS OF CATEGORIZING THEM */ %LET TYPEWANT=%STR(('M' '1' '2' '3' '6' '9' ' '));
/* DETERMINE IF DATE IS BETWEEN WANTED DATES */ IF &DT4SLCTN='A' THEN DO; IF ADMIT_DT < &FROMDT OR ADMIT_DT > &TODT THEN DO; DATEDEL=DATEDEL+1; DELETE; END; END; ELSE IF &DT4SLCTN='D' THEN DO; IF DISCH_DT < &FROMDT OR DISCH_DT > &TODT THEN DO; DATEDEL=DATEDEL+1; DELETE; END; END; ELSE DO; IF DISCH_DT < &FROMDT OR ADMIT_DT > &TODT THEN DO; DATEDEL=DATEDEL+1; DELETE; END; END; /* DETERMINE IF SEX = SELECTION TYPE */ IF SEX IN ('1' '3' 'M') THEN SEX1=1; ELSE SEX1=2; IF &SLCTTYPE IN (1 2) AND SEX1 NE &SLCTTYPE THEN DO; SEXDEL=SEXDEL+1; DELETE; END;
/* DETERMINE WHICH MACRO TO RUN BASED ON ICD CODING */ IF IC10D1 > ' ' THEN DO; %ICD10PROC; END; ELSE DO; %ICD9PROC; END;
%MACRO ICD9PROC; J = 1; DO UNTIL (J > 25); /* DETERMINE IF RECORD IS TO BE SELECTED */ IF J LE &CODEICD AND TYPE{J} IN %STR(&TYPEWANT) THEN ICDWANT=1; END; ELSE DO; END; END; %MEND ICD9PROC; TYPEO{J}=' '; ICDFMT{J}=' ';
Variation on the theme
%MACRO FILEREAD(FLNAME); DATA T1(KEEP=VAR1 VAR2 VAR3); INFILE "/SAS_data/pathname/morepathname/&FLNAME..dat" LRECL=2916 MISSOVER PAD EOF=LAST; INPUT @1 var1 $1. @2 var2 1. @3 var3 $CHAR3.; %MEND FILEREAD; %FILEREAD(y0708/y0708); %FILEREAD(y0809/y0809);
Conditional Programming In A Macro Outside of Regular Data/Proc Statements
Like basic SAS programming but use the % before each word %if, %then, %do
%macro xtr(year,type); %let sufx= ; *Note: this equates to a null value; %if (&type = main and ((&year = 0102) or (&year = 0203) %then %let sufx=a; data s1; set s&year..&type&year&sufx ; date = dos-1; *Adjusted SAS date to Perpetual from Health Perpetual; if amt_app NE. and dos GE &strdate. and dos LT &enddate. AND (diag IN(&slctdiag.)) ; proc append base=&result data=s1 force; proc delete data=s1; run; %mend; /*** Macro calls to stats files ***/ %xtr(year=1415,type=main);
More Examples
%let input = data.t201602; %let effdate = 20160101; %let fiscal = '01Apr2016'd; %let year = 2016; %let month = 06; * Specify the fields required in the report; %let fields= run_cd, rx_ddddd, drg_type, hsn variable list.; * Call the creation macro and create the source data file; %creation (&input) %let source=source; * Invoke the ReportX program; %include '/SAS_data/drugplan/Data/Production/ReportX.sas'; run;
%macro creation(quarter); proc sql; create table new as select &fields from &quarter; quit; proc append base=source data=new force; run; proc sql; drop table new; quit; %mend;
* Create table - - Males Report X; %let sex = 'M'; %let cov = 1; %let infile = output; %let outfile = '/SAS_data/path/name/ReportX1M.asc'; %include '/SAS_data/path/name/Programs/ReportXExport.sas'; * Create table - - Females Report X; %let sex = 'F'; %let cov = 1; %let infile = output; %let outfile = '/SAS_data/path/name/ReportX1F.asc'; %include '/SAS_data/path/name/Programs/ReportXExport.sas'; * Create table - - All Report X; %let sex = sex; %let cov = 1; %let infile = output; %let outfile = '/SAS_data/path/name/ReportX1All.asc'; %include '/SAS_data/path/name/Programs/ReportXExport.sas';
ReportXExport.sas proc sql; create table output as select * from getdata where cov = &cov and sex = &sex; quit; Data _null_; set &infile; file &outfile; put ; Run;
%let pct=0.034; %let pcta= 3.4%'; Data T1; set x; threshhold=5*ceil((calc_income*&pct/2)/5); dmc=round((calc_income*&pct)/12,.01); Run; *outputting results in log; data _null_; set T1; put @1 'Output for ' &pcta; put @1.;
%let startno = 1; %let endno = 3; %macro printvar; data _null_; array test (2) test1-test2; do i = &startno to &endno; test(i) = i; end; run; %mend printvar; %printvar; run;
17 %let startno = 1; 18 %let endno = 3; 19 20 %macro printvar; 21 22 data _null_; 23 24 array test (2) test1-test2; 25 26 do i = &startno to &endno; 27 test(i) = i; 28 end; 29 run; 30 31 %mend printvar; 32 33 %printvar; ERROR: Array subscript out of range at line 33 column 85. test1=1 test2=2 i=3 _ERROR_=1 _N_=1 NOTE: The SAS System stopped processing this step because of errors. NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds
Options for Debugging: SYMBOLGEN/NOSYMBOLGEN - displays of value of the variables MPRINT/NOMPRINT - shows what the compiler receives MLOGIC/NOMLOGIC - displays tracing of macro execution.
options symbolgen; %let startno = 1; %let endno = 3; %macro printvar; data _null_; array test (2) test1-test2; do i = &startno to &endno; test(i) = i; end; run; %mend printvar; %printvar; run;
15 options symbolgen; 16 17 %let startno = 1; 18 %let endno = 3; 19 20 %macro printvar; 21 22 data _null_; 23 24 array test (2) test1-test2; 25 26 do i = &startno to &endno; 27 test(i) = i; 28 end; 29 run; 30 31 %mend printvar; 32 33 %printvar; SYMBOLGEN: Macro variable STARTNO resolves to 1 SYMBOLGEN: Macro variable ENDNO resolves to 3 ERROR: Array subscript out of range at line 33 column 85. test1=1 test2=2 i=3 _ERROR_=1 _N_=1
15 options mprint; 16 17 %let startno = 1; 18 %let endno = 3; 19 20 %macro printvar; 21 22 data _null_; 23 24 array test (2) test1-test2; 25 26 do i = &startno to &endno; 27 test(i) = i; 28 end; 29 run; 30 31 %mend printvar; 32 33 %printvar; MPRINT(PRINTVAR): data _null_; MPRINT(PRINTVAR): array test (2) test1-test2; MPRINT(PRINTVAR): do i = 1 to 3; MPRINT(PRINTVAR): test(i) = i; MPRINT(PRINTVAR): end; MPRINT(PRINTVAR): run; ERROR: Array subscript out of range at line 33 column 85. test1=1 test2=2 i=3 _ERROR_=1 _N_=1
15 options mlogic; 16 17 %let startno = 1; 18 %let endno = 3; 19 20 %macro printvar; 21 22 data _null_; 23 24 array test (2) test1-test2; 25 26 do i = &startno to &endno; 27 test(i) = i; 28 end; 29 run; 30 31 %mend printvar; 32 33 %printvar; MLOGIC(PRINTVAR): Beginning execution. ERROR: Array subscript out of range at line 33 column 85. test1=1 test2=2 i=3 _ERROR_=1 _N_=1 NOTE: The SAS System stopped processing this step because of errors. NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds MLOGIC(PRINTVAR): Ending execution.
15 options symbolgen mprint mlogic; 17 18 %let startno = 1; 19 %let endno = 3; MLOGIC(PRINTVAR): Beginning execution. MPRINT(PRINTVAR): data _null_; MPRINT(PRINTVAR): array test (2) test1-test2; SYMBOLGEN: Macro variable STARTNO resolves to 1 SYMBOLGEN: Macro variable ENDNO resolves to 3 MPRINT(PRINTVAR): do i = 1 to 3; MPRINT(PRINTVAR): test(i) = i; MPRINT(PRINTVAR): end; MPRINT(PRINTVAR): run; ERROR: Array subscript out of range at line 34 column 85. test1=1 test2=2 i=3 _ERROR_=1 _N_=1 NOTE: The SAS System stopped processing this step because of errors. NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds MLOGIC(PRINTVAR): Ending execution.
References: Online support.sas.com documentation Steven First & Katie Ronk, SAS Macro Variables and Simple Macro Programs Paper 130-30, http://www2.sas.com/proceedings/sugi30/130-30.pdf