{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;} {\f32\froman\fcharset238\fprq2 Times New Roman CE;}{\f33\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f35\froman\fcharset161\fprq2 Times New Roman Greek;}{\f36\froman\fcharset162\fprq2 Times New Roman Tur;} {\f37\froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f38\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f39\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f48\fmodern\fcharset238\fprq1 Courier New CE;} {\f49\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f51\fmodern\fcharset161\fprq1 Courier New Greek;}{\f52\fmodern\fcharset162\fprq1 Courier New Tur;}{\f53\fmodern\fcharset177\fprq1 Courier New (Hebrew);} {\f54\fmodern\fcharset178\fprq1 Courier New (Arabic);}{\f55\fmodern\fcharset186\fprq1 Courier New Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0; \red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{ \ql \li0\ri0\widctlpar\nooverflow\faroman\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{\*\cs10 \additive Default Paragraph Font;}{\*\cs15 \additive \ul\cf2 \sbasedon10 Hyperlink;}}{\info{\title (Yet Another} {\author Frank DiIorio}{\operator Andrew Ratcliffe}{\creatim\yr2000\mo3\dy23\hr19\min56}{\revtim\yr2000\mo3\dy23\hr20\min6}{\version3}{\edmins1}{\nofpages2}{\nofwords672}{\nofchars3833}{\*\company AIMS, Co.}{\nofcharsws0}{\vern8247}} \margl720\margr720\margt720\margb720 \widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\lytprtmet\hyphcaps0\formshade\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow1\dgvshow0 \jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\bdrrlswsix\nolnhtadjtbl\oldas \fet0\sectd \linex0\endnhere\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}} {\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (} {\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \qc \li0\ri0\widctlpar\nooverflow\faroman\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\b (Yet Another!) Observation-Counting Macro \par }{Frank DiIorio \par AIMS, Co. \par Durham, North Carolina, USA \par }\pard \ql \li0\ri0\widctlpar\nooverflow\faroman\rin0\lin0\itap0 { \par A common requirement of even basic utility and report-writing macros is determining the number of observations in a SAS dataset. The macro presented here uses SAS\rquote dictionary tables to determine both the number of observations and the existence of the dataset. If the macro looked only at the TABLES table variable NOBS, a zero value could mean either no observations in a valid/present dataset }{\i or }{ that the dataset doesn\rquote t exist. The COUNTOBS macro distinguishes between these two possibilities and returns a value of \endash 1 if the dataset does not exist, or 0 or greater if the dataset exists. Here is the code. Refer to the comment header for usage details. \par \par }{\f2\fs16\cf1 /* \par \par COUNTOBS.SAS \par Counts number of observations in a SAS dataset and returns the \par value in a Global macro variable. \par \par Parameters \par ======================================================================= \par \par Name Status Default Description \par -------- ------ ------- -------------------------------------------- \par datastor req One or two-level name of dataset/view to \par examine. \par count opt _count_ Name of macro variable containing return code. \par -1 = Dataset doesn\rquote t exist \par >=0 = Number of obs \par \par */ \par \par }{\b\f2\fs16\cf1 %macro }{\b\i\f2\fs16\cf1 countobs}{\b\f2\fs16\cf1 (datastor=, count=_count_); \par }{\f2\fs16\cf1 %local dataok; \par %global &count; \par \par * Fold to upper case and break into LIBNAME and member name ; \par %let datastor = %upcase(&datastor); \par %if %index(&datastor, }{\b\f2\fs16\cf1 .}{\f2\fs16\cf1 ) > }{\b\f2\fs16\cf1 0}{\f2\fs16\cf1 %then %do; \par %let libname = %scan(&datastor, 1, .); \par %let memname = %scan(&datastor, 2, .); \par %end; \par %else %do; \par %let libname = WORK; \par %let memname = &datastor; \par %end; \par \par * WH is used twice in SQL that follows, so make it a macro \par variable for easier maintenance. ; \par %let wh = where libname = "&libname" & \par memname = "&memname" & \par \tab memtype = "DATA" \par \tab \tab \tab \tab ; \par \par * This SQL generated by macro COUNTOBS; \par proc sql noprint; \par select nobs into :&count from dictionary.tables &wh; \par select count(nobs) into :dataok from dictionary.tables &wh; \par quit; \par \par * If no members, change the 'no observations' 0 value of COUNT \par to the 'no tables/datasets' value of count. ; \par %if &dataok = }{\b\f2\fs16\cf1 0}{\f2\fs16\cf1 %then %let &count = -1; \par %put COUNTOBS: Count variable %upcase(&count)=%left(&&&count); \par %mend; \par }{\f2\fs16 }{ \par A macro such as COUNTOBS is usually called within another macro. Here is a simple example of its use. In the example, we create dataset X. In \'93real life\'94 we would assume it was already created, hence the need for the observation-counting macro. \par \par }{\f2\fs16\cf1 %macro report; \par data x; \par var = 1; \par run; \par \par %countobs(datastor=x, count=n); \par %if &n > 0 %then %do; \par proc print data=work.x; \par \tab run; \par %end; \par %else %if &n = 0 %then %do; \par \tab data _null_; \par \tab file print; \par \tab put "Dataset WORK.X was empty!"; \par \tab run; \par \tab %end; \par %else %if &n = -1 %then %do; \par \tab data _null_; \par \tab file print; \par \tab put "Dataset WORK.X could not be located!"; \par \tab run; \par \tab %end; \par %mend; \par }{\f2\fs20\cf1 \par }{When we run REPORT in this, the 1-observation, case we get the following SAS Log. Since the dataset was found, and had more than 0 observations, the PRINT procedure was executed (the output is uneventful, and is not shown here). \par \par }{\f2\fs16 MPRINT(REPORT): data x; \par MPRINT(REPORT): var = 1; \par MPRINT(REPORT): run; \par \par NOTE: The data set WORK.X has 1 observations and 1 variables. \par NOTE: DATA statement used: \par real time 0.04 seconds \par \par \par MPRINT(COUNTOBS): * This SQL generated by macro COUNTOBS; \par MPRINT(COUNTOBS): proc sql noprint; \par MPRINT(COUNTOBS): select nobs into :n from dictionary.tables where libname = "WORK" & memname \par = "X" & memtype = "DATA"; \par MPRINT(COUNTOBS): select count(nobs) into :dataok from dictionary.tables where libname = \par "WORK" & memname = "X" & memtype = "DATA"; \par MPRINT(COUNTOBS): quit; \par NOTE: PROCEDURE SQL used: \par real time 0.06 seconds \par \par \par COUNTOBS: Count variable N=1 \par MPRINT(REPORT): ; \par MPRINT(REPORT): proc print data=work.x; \par MPRINT(REPORT): run; \par \par NOTE: There were 1 observations read from the dataset WORK.X. \par NOTE: PROCEDURE PRINT used: \par real time 0.00 seconds \par }{ \par There are many other possible extensions to this simple macro. The macro could have a \'93resolve view\'94 parameter which would check to see if the DATASTOR value is a view and then resolve the view (create a temporary dataset) and count the observations (recall that a view is a \'93virtual\'94 dataset and so does not have observations }{\i per se}{ ). Other extensions, such as parameter checking, would make the macro more robust. \par \par Send your comments or questions to the author at }{\field\fldedit{\*\fldinst {HYPERLINK "mailto:fcd1@mindspring.com"}{{\*\datafield 00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b360000006d00610069006c0074006f003a00660063006400310040006d0069006e00640073007000720069006e0067002e0063006f006d000000}}}{\fldrslt {\cs15\ul\cf2 fcd1@mindspring.com}}}{. \par }}