The description of the NOTDIGIT function says that NOTDIGIT function searches a string for the first occurrence of any character that is not a digit. If such a character is found, NOTDIGIT returns the position in the string of that character. If no such character is found, NOTDIGIT returns a value of 0.
So, IF your character variable has all numbers, then the DO block will NOT be executed. However, more about this later.
In your original post, you said:
i'm stepping through a data step with 20 vars and i have a if / then condition that determines to call the macro or not.
if notdigit(prod,1) > 0 then
this code calls the macro every step through the data step. is there another way to conditionally process this?
This code does NOT call the macro program or not. Your macro code is NOT being executed conditionally...not exactly. There is a HUGE difference between a macro %IF/%DO and a regular DATA step program with a %mac invocation. When you have the kind of syntax that you show, essentially, at compile time, all your %sel(...) invocations are being expanded into code like this (shown for PROD and CRED variables). This expansion (or resolution) happens at code COMPILE time. So by the time your program executes, these are the complete sets of IF statements that SAS is actually executing or not executing:
** for PROD section of code;
if notdigit(prod,1)> 0 then
if bad_dig ne '.' then
keep prod bad_var;
** for CRED section of code;
if notdigit(cred,1)> 0 then
if bad_dig ne '.' then
keep cred bad_var;
So by the time SAS executes these statements, the DO block contained in the %SEL macro program will be executed based on the NOTDIGIT test in the DATA step IF statement. So the resolved statements are only going to be executed AT ALL if the results of using the NOTDIGIT function return a result greater than 0.
That being the case, let's turn our attention to the NOTDIGIT function. If you are using the NOTDIGIT function on a character variable, unless your numbers fill the entire length of the variable, you might be surprised to find that you get different results for the value of the NOTDIGIT function, depending on whether you have trailing blanks in the character variable value (which is possible). Consider the following program:
length string $20;
input string $;
Note that I have given the STRING variable an explicit length of 20 characters, yet of my 5 observations, only the last observation completely uses up all 20 positions allocated to the variable length. The TEST1 variable uses the NOTDIGIT function with the TRIM function (to strip off trailing blanks (because a character variable that does not "fill" its length will be padded to the right with blanks). The TEST2 variable uses the NOTDIGIT function in the same way that you do in your program, without trimming or stripping out the trailing blanks. The SAS log shows different values for the TEST1 vs the TEST2 variable:
=======>string=11a1 test1=3 test2=3
=======>string=2222 test1=0 test2=5
=======>string=333z3 test1=4 test2=4
=======>string=4444 test1=0 test2=5
=======>string=12345678901234567890 test1=0 test2=0
As you can see from my results, shown in the log, that observation 2 (2222) and observation 4 (4444) in the untrimmed comparison show a value for TEST2 of 5 -- which would be the position of the first blank that pads the character variable value. So, that means it is possible for your NOTDIGIT function to return a value greater than 0 for your character variables, unless you are absolutely sure that your variable values completely fill up the length of the variable field.
Rather than focus on whether or not your macro code is being called conditionally, one thing to do would be to make your code more efficient. For example,by my count, your program is generating a call to the NOTDIGIT function possibly 3 times -- for EVERY variable you test. It would be more efficient to do execute the NOTDIGIT function one time, make a temporary variable and then test this temporary variable or use it in further function calls (like the SUBSTR function) -- something like this:
notdig_val = notdigit(trim(prod),1); /* execute the NOTDIGIT function one time */
if notdig_val> 0 then
if bad_dig ne '.' then
keep prod bad_var;
This change for efficiency purposes might mean that you need to redesign your macro program code a bit. Just remember that the macro processor is just acting like a big typewriter and that your %sel(...) macro program invocation is being resolved or expanded at code COMPILE time -- by the time your program executes, all the %sel(...) references are gone and have been replaced by the now complete DATA step IF statement. Your macro program is just saving you some tedious typing or repetitive statements for every variable you want to test.
When you say: "The macro is working but not quite like I wanted."
it's hard to envision what you mean. The output dataset does not contain what you think it will contain? The wrong observations are getting written? You're getting messages in the log?
One way to ensure that your macro program WILL work the way you want is to start with a working SAS program that generates the desired results (yes, even if it means you have to hard-code 20 IF statements). If you refine your logic in a program that does NOT have any macro triggers or macro code, then when you "macro-ize" the working code you have a better chance of the resolved macro code working the way you intend.
The first thing we recommend to anyone who takes the Macro class is that you should NOT write or use a single & or % in your code until you have a program that produces exactly the output you want, as described in this paper: http://www2.sas.com/proceedings/sugi28/056-28.pdf
Do you have working code, with ELSE IF conditions (and WITHOUT any macro calls) that either generates the error or does not generate the error?? There is something about your generated code that is making the ELSE IF condition complain about not having a matching IF condition.
What I would recommend is to make a subset of data with just 3 columns and then hardcode the program with IF/THEN/ELSE statements and your NOTDIGIT test to see what statements work correctly and generate the desired results. Then, macro-ize that working program and make sure that the new program, with macro calls is still error free. There should be something different between the working "unmacro-ized" code and the code generated by your macro program that will point you in the right direction.
You have placed a semicolon after the macro call. This semicolon is eventually added to the second END, which is then END;; This null statement interrupts the IF-THEN/ELSE sequence thus isolating the ELSE. The solution is to call the macro without the semicolon.
We really need to see the rest of your DATA step which would precede the macro invocation - suggest you paste the entire SAS-generated log output as a post/reply, but after verifying the DATA step logic yourself, for an extra END; statement of some type, before your RUN; or the next PROC / DATA step.