I think I have myself quite confused about when to use a single quote, double-quote, single ampersand and double ampersand in relation to using parameters in and outside macros.
I am writing a stored process with macros that will allow a user to choose 1, 2 or 3 reports - call them Report1, Report2 and Report3. My thought is/was I could cycle through the choices with a DO FROM 1 %superq(CHOICE0) routine, setting up my choices accordingly:
At the end of my stored process, I have the following code to process either 1, 2 or 3 reports:
%if &ReportChoice1 = Year_Range %then %do;
%put am in Report Type A;
%if &ReportChoice2 = Colleges %then %do;
%put am in Report Type B;
%if &ReportChoice3 = Positions %then %do;
%put am in Report Type C;
However..... I get the following error message:
MLOGIC(REPORTTYPES): Beginning execution.
MPRINT(REPORTTYPES): data check;
WARNING: Apparent symbolic reference REPORTCHOICE1 not resolved.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: &ReportChoice1 = Year_Range
ERROR: The macro REPORTTYPES will stop executing.
MLOGIC(REPORTTYPES): Ending execution.
Can anyone please help me with fixing my confusion??? Perhaps I should get away from macros??? Thanks!
Macros are extremely powerful. As I've said before, they can get complicated enough if you're new to Macro programming, and even seem more complicated if you're new to SAS programming and new to Macros at the same time. But there are a few rules that help make understanding macro easier and they are outlined in the Macro documentation. In summary, they are:
1) Code that contains macro triggers (% and &) is "preprocessed" by the macro wordscanner and any macro references are resolved, substitution is performed and then the final, resolved code is sent to the SAS compiler for regular compile and execute phase.
2) Because of this behavior, consider the macro processor to be acting like a typewriter. If you have
%let amt = 500; (or any other method of assigning a value to a macro variable is used)
then, when the macro wordscanner sees this line
if sales gt &amt;
then substitution or typing is performed and the final statement sent to the compiler is:
if sales gt 500;
3) The macro wordscanner "peeks" inside quoted strings to check for macro references and triggers -- BUT it will ONLY peek inside strings quoted with double quotes (") So ANYTIME you use single quotes (') your macro references and triggers will not be seen by the macro wordscanner and no substitution will happen.
4) There are "rules" to when and how macro variable references are resolved. One such rule is the "Forward Scan Rule"; another such rule is the "Rescan" Rule. When you directly reference a macro variable, such as &AMT, there is a very straightforward lookup done (in the Global Symbol Table) for that value. But what if you have "numbered" macro variables, such as &CHOICE1, &CHOICE2 and &CHOICE3??? If you refer to them directly with their numbers intact, you may only need a single &. However, if you refer to them indirectly, then the 2 above rules apply. Those two rules are described in the macro documentation under a topic entitled "Referencing Macro Variables Indirectly". When you reference macro variables indirectly, you may need to use multiple ampersands, such as &&CHOICE&NUM
5) There are also rules or situations that involve the need for macro quoting functions, such as %QUOTE, %UNQUOTE, %SUPERQ, etc because sometimes you need to "mask" or "hide" certain special characters (like % and & or logical operators) from being seen or resolved in the code prematurely. There is another documentation topic entitled "Deciding When to Use a Macro Quoting Function and Which Function to Use" that explains how the quoting functions work.
6) Speaking further of quotes, appropriate usage of quote characters inside any generated SAS code requires that you have a working SAS program. For example, given this program:
proc print data=sashelp.shoes noobs;
where region = "Asia" and sales gt 5000;
I need quotes around the region, Asia, because the WHERE statement is doing a comparison to a character variable. I do NOT need quotes around the 5000 because the WHERE statement is doing a comparison to a numeric variable. So once I have a working SAS program, with all the quotes in the right places, I can start to insert macro variable references, like this:
proc print data=&lib..&dsn noobs;
where region = "&wantreg" and sales gt &amt;
7) In order to code an effective macro program -- one that works -- the best situation is to understand WHAT your final resolved SAS code will look like. So, for example, in your %ReportTypes macro program, your macro program starts with the generation of the code "data check", followed by an invocation of another macro program called %sort_A -- so what code do you expect to send to the SAS compiler??? Since the data step won't perform a sort, I'm wondering what you intend your final, generated program code to look like. In fact, both of your macro programs, after the %macro statement start with DATA statements and I wonder why. A macro program does not automatically mean you need a DATA step program.
I count the following 7 calls to macro programs in your code snippet:
And although I see a macro program definition for %macro ReportTypes, I do not see a call to invoke %ReportTypes. In order to really debug this set of linked macro programs, someone really needs to look at the way ALL the macro programs are written. Not just %MACRO FIELD_WHERE or %MACRO REPORTTYPES, but also the macro programs for %sort_A and for %Report_B. Someone needs to look at the entire SAS program that you started with to see whether it's been converted to macro code in the best manner.
I don't think you need to necessarily get away from macro programs, so much as you need to start with a working SAS program that does 1 piece of your task - get that program working -- then convert that piece of program to a macro program. Just going through that process will teach you a LOT about SAS programming and Macro processing. However, this code is not a working SAS program:
proc sort data=sashelp.shoes;
if sales gt 5000 then bonus = 100;
So there would be no point in turning the above code into a macro program because if it has errors in "regular" SAS or EG, it will still have errors when I turn it into a macro program. At this point, it is nearly impossible for anyone to look at the code snippets that you can post to the forum and really provide much substantive help, because to debug macro, we'd need to see all the %MACRO definitions as well as your starting SAS program to see how you'd done the conversion.
The people best suited to looking at an entire set of related programs and helping you resolve your macro questions and SAS programming questions are the people in Tech Support.
I got the code working, simply by making sure I was looking at the correct variables. In my first macro, I had &Report1, &Report2 and &Report3 but in my report generating macro I had &ReportType1, &ReportType2 and &ReportType3.
In other words, the report generating macro was using empty variables. This was a simple case of not doing thorough desk-checking!
In any case, I again thank you for your detailed reply and want to let you know you are helping tremendously to increase my SAS knowledge. Did someone say Dashboards? That'll probably be my next mountain.