Suppose you have an old jalopy that's perfectly reliable. Your jalopy gets you where you wanna go: no frills; no drama.
Do you trade your old wheels in for a racecar that accelerates like crazy and corners like it's on rails?
Or stick with what's old and comfortable? Your choice depends on whether you need the extra speed and capability and, of course, the price.
Here's a jalopy macro that issues SQL code to populate a macro variable with an observation count from a selected dataset:
%macro numobs(dsn); %let dsn=%upcase(&dsn); %global numobs; proc sql noprint; select nobs into :numobs from dictionary.tables where libname="%scan(&dsn,1)" & memname="%scan(&dsn,2)"; quit; %mend numobs; |
This jalopy macro does the same thing using the DATA step instead of SQL:
%macro numobs(dsn); data _null_; call symputx('numobs', number,'G'); stop; set &dsn nobs=number; run; %mend numobs; |
Both jalopy macros work just fine. Why should you trade either one for a racecar macro? If I were a slick car salesman, or a slick macro salesman, here's what I would say:
The jalopy macros work, but they're indirect, inefficient, and inflexible.
How so? Because they both place sascode on the input stack.
Why is that indirect and inefficient? Because, once on the input stack, sascode must be
- tokenized
- compiled
- executed
Why are they inflexible?
Because they cannot be called from within SAS code. For example, you cannot do this:
TITLE "%numobs(orion.order_fact) observations"; |
In addition, they cannot be called in-line within a macro language statement. For example, you cannot do this:
%if %numobs(orion.order_fact)>10 %then %do; |
Neither jalopy macro works like a macro function. A macro function returns a value and can be called anywhere. A macro function can also be called in-line.
So how do I turn a jalopy macro into a tire-squealing racecar macro?
- Eliminate all SAScode
- Replace the SAScode with pure macro language code
- Use SAS I/O functions as needed
Using the above technique, you can create your own macro utility functions that return whether a dataset exists, the number of observations in a dataset, the number of observations in a subset, the age of a dataset, a SAS variable's type, a SAS variable's label, a formatted value of a macro variable, etc. To learn more, attend our tire-squealing new course ... SAS Macro Language 2: Advanced Techniques.
9 Comments
1) The code for "No. of obs" can sometimes be shortened to (without any error handling) :
%PUT "Antal obs:" %sysfunc(attrn(%sysfunc(open(test)),nobs));
2) A question: Is there any good way in Windows Explorer to see "No. of obs" and "No of var" in a SAS Table ? (without using SAS Universal Viewer)
Many years ago we had a command on IBM ISPF 3.4 panel called SASTAB, which told us all the SAS tablenames and "No of var" and "No of obs", in each SAS table.
/ Br Anders Sköllermo (Andrew Skollermo in English)
1) This works. Two suggestions: a) follow with the CLOSE function; b) remove the quotation marks.
2) Sorry, I do not know of a way.
Thanks, Anders, for posting.
jim
I'm disappointed that you would tease us with a problem and not provide the solution. I presume that the course would teach some variant of http://support.sas.com/kb/24/671.html , such as the following.
Yes, very much like your example, Rick. Using many of the same tools. Only slicker. More robust. And more versatile. With multiple examples.
And, yes, I admit, my post is a bit of a tease. I want you to come to class to learn this trick and many more. Or attend my SGF advanced macro pre-conference tutorial in two months. : )
The other alternative is to not use macros at all - no code substitution, tokenization, etc - and instead create a user-defined function using PROC FCMP..
Thank you, Andrew, for your post. PROC FCMP is indeed a wonderful tool, but is not always a macro replacement. A call to a PROC FCMP created function must be tokenized, compiled, and executed just like any other sascode. The compiled PROC FCMP created function must also execute. This usually occurs on a row-by-row basis while reading a SAS dataset. A macro function, on the other hand, excutes one-time-only when called, so it is potentially far more efficient. Finally, a PROC FCMP created function can be called wherever a function can be called, while a macro function can be called anywhere; within a TITLE statement, for example.
surprised to hear The Suggestion that a function cannot execute in a title statement?
Isn't that the "new" feature introduced only 20+ years ago in SAS9.07e?
(if you haven't guessed or don't quite recall, that feature was
Title "%sysfunc(almost_any_function(),format_for_numeric_function_results)";
which might be a great way of placing time stamp and metadata into report endnotes.
/end.smug.smiley
the old fool!
It was SAS6.09e
!
absolutely right, Peter. thru the magic of %SYSFUNC. thanks for posting!
jim