宏将行计数作为值

时间:2018-03-01 16:30:24

标签: sas

我想定义nrow以便能够调用:

%put %nrow(sashelp.cars);

也许有现有的功能或一些简单的解决方案,但我还没有找到它。

从给出不同形式行数的online solutions我尝试了这些但没有成功:

%macro nrow1(data);
 %local n;
 data _null_;
  set &data NOBS=size;
  call symput("n",size);
 stop;
 run;
 &n
%mend;

%macro nrow2(data);
 %local n;
 PROC SQL;
   select count(*) as n into :n from &data;
 QUIT;
 &n
%mend;

%macro nrow3(data,lib);
  %local n;
  proc sql;
    select nobs into :n
    from dictionary.tables
    where libname eq "&lib"
    and memname eq '&table';
    quit;
  &n
%mend;

如何纠正这些?

3 个答案:

答案 0 :(得分:3)

制作这种类型的宏"功能"结果文本必须是宏生成的唯一文本。您的测试代替生成SAS代码。因此,当您在%put语句中使用它们时,第一个SAS语句成为%put语句的一部分。

你需要在宏中只使用宏语句而不是SAS语句,以便在语句中间使用它。

您可以使用此宏。 https://github.com/sasutils/macros/blob/master/nobs.sas 如果可用,将使用元数据,否则通过逐行获取数据来计算观察数。它当前默认使用count创建一个宏变量,但可以在没有宏变量名的情况下调用它,甚至可以将宏定义修改为默认为不使用宏变量名。

%macro nobs
/*----------------------------------------------------------------------
Return the number of observations in a dataset reference
----------------------------------------------------------------------*/
(data       /* Dataset specification (where clauses are supported) */
,mvar=nobs  /* Macro variable to store result. */
            /* Set MVAR= to use NOBS as an in-line function. */
);
/*----------------------------------------------------------------------
Usage:

When the MVAR parameter is empty then NOBS will return the result as
the output of the macro call so that NOBS can be called in a %IF or
%LET statement. See examples.

------------------------------------------------------------------------
Examples:

%* Generating the default macro variable ;
%nobs(EVENTS)
%if (&nobs = -1) %then %put %sysfunc(sysmsg()) ;
%else %if (&nobs > 0) %then %do;
  ....

%* Use without generating macro variable ;
%if (%nobs(EVENTS,mvar=) > 0) %then %do;
  ....

%* Generating a different macro variable and use WHERE clause ;
%nobs(demog(where=(sex=1)),mvar=nmales)
%put Number of males = &nmales;

------------------------------------------------------------------------
Notes:

NOBS will return -1 when it cannot count the number of observations.
You can use %sysfunc(sysmsg()) to get the reason.

The macro variable specified in the MVAR parameter is globalized if not
previously defined in the calling environment.

When the DATA parameter is not specified, the last created data file is
used.

In the rare case that NLOBSF function cannot count the observations
then the NOBS macro will loop through the dataset and count.
Testing so far has found that sequential datasets such as V5 transport
libraries cannot use the NLOBSF function. For large sequential datasets
you will get faster results using an SQL query instead of NOBS macro.

-----------------------------------------------------------------------
History:
03DEC95  TRHoffman  Creation
12JUL96  TRHoffman  Protected against different values of MISSING
                    option.
20AUG97  TRHoffman  Protected against case changes in options table.
11MAR99  TRHoffman  Trimmed the returned macro variable. (Recommended
                    by Paulette Staum). Used macro mvartest to globalize
                    previously undefined variables.
25OCT2000 abernt    Updated to handle lowercase letters in where clause
                    and eight character libnames. Eliminated need to
                    use %TRIM() macro.
14OCT03  TRHoffman  Used qupcase function to permit macro variables in
                    where clause.
09JAN2009 abernt    Changed to use ATTRN functions. Test MVAR value.
                    Return results like a function when MVAR is blank.
01MAR2018 abernt    Removed usage of sasname and mvartest macros.
----------------------------------------------------------------------*/
%local dsid return ;

%if %length(&mvar) %then %do;
%*----------------------------------------------------------------------
MVAR parameter must be a valid variable name.
-----------------------------------------------------------------------;
  %if not %sysfunc(nvalid(&mvar)) %then %do;
    %put %str( );
    %put ERROR: Macro NOBS user error.;
    %put ERROR: "&mvar" is not a valid value for MVAR. Must be a valid SAS name.;
    %goto quit;
  %end;
%*----------------------------------------------------------------------
MVAR paramater cannot duplicate a variable name used by NOBS macro.
-----------------------------------------------------------------------;
  %if %sysfunc(indexw(DATA MVAR DSID RETURN,%upcase(&mvar))) %then %do;
    %put %str( );
    %put ERROR: Macro NOBS user error.;
    %put ERROR: "&mvar" is not a valid value for MVAR. Name in use by NOBS macro.;
    %goto quit;
  %end;
%*----------------------------------------------------------------------
Globalize macro variable when not defined.
-----------------------------------------------------------------------;
  %if not %symexist(&mvar) %then %global &mvar ;
%end;

%*----------------------------------------------------------------------
When DATA parameter not specified, use &syslast macro variable to get
last created data set.
-----------------------------------------------------------------------;
%if %bquote(&data) =  %then %let data=&syslast;

%*----------------------------------------------------------------------
DATA=_NULL_ will successfully OPEN, but cannot be queried with ATTRN
function. So by setting DATA=*_NULL_* the OPEN call will fail and set
an error message that can be retrieved with the SYSMSG() function.
-----------------------------------------------------------------------;
%if (%qupcase(&data) = _NULL_) %then %let data=*_NULL_*;

%*----------------------------------------------------------------------
Initialize for failure.
-----------------------------------------------------------------------;
%let return=-1;

%*----------------------------------------------------------------------
Open the dataset for random access.
  When there are no active where clauses then use NLOBS.
  If that did not get a count then try NLOBSF.
-----------------------------------------------------------------------;
%let dsid = %sysfunc(open(&data));
%if &dsid %then %do;
  %if not %sysfunc(attrn(&dsid,WHSTMT)) %then
    %let return = %sysfunc(attrn(&dsid,NLOBS));
  %if (&return = -1) %then %let return = %sysfunc(attrn(&dsid,NLOBSF));
  %let dsid = %sysfunc(close(&dsid));
%end;

%*----------------------------------------------------------------------
If unable to get a count then try to open dataset for sequential access
and count observations by fetching each one.
-----------------------------------------------------------------------;
%if (&return = -1) %then %do;
  %let dsid = %sysfunc(open(&data,IS));
  %if &dsid %then %do;
    %let return=0;
    %do %while (%sysfunc(fetch(&dsid)) = 0);
      %let return = %eval(&return + 1);
    %end;
    %let dsid = %sysfunc(close(&dsid));
  %end;
%end;

%*----------------------------------------------------------------------
Return the value.
-----------------------------------------------------------------------;
%if %length(&mvar) %then %let &mvar=&return;
%else &return;

%quit:
%mend nobs;

答案 1 :(得分:1)

这将返回数据集中的总行数。如果数据集不存在(或者如果它是视图),则为-1。您可以选择包含where语句。由于SAS需要重新计算整个表格,因此where语句将显着降低性能。

%macro nrow(data, where=);

    %if(%index(%sysfunc(compress(&data.)), %bquote(where=))) 
        %then %let option = nlobsf;
    %else %let option = nlobs;

    %if(%sysfunc(exist( %scan(&data., 1, %str(%() ) ) ) ) %then %do;
        %let dsid   = %sysfunc(open(&data.) );
        %let n      = %sysfunc(attrn(&dsid, &option.) );
        %let rc     = %sysfunc(close(&dsid) );
    %end;
        %else %let n=-1;

    &n.;
%mend;

答案 2 :(得分:1)

以下是Stu代码的更新,可为您提供所需内容。请注意%local声明,这样您就不会有额外的宏。

%macro get_nobs(data);
    %local option dsid nobs rc;

    %if(%index(%sysfunc(compress(&data.)), %bquote(where=))) 
        %then %let option = nlobsf;
    %else %let option = nlobs;

    %if(%sysfunc(exist( %scan(&data., 1, %str(%() ) ) ) ) %then %do;
        %let dsid   = %sysfunc(open(&data.) );
        %let nobs  = %sysfunc(attrn(&dsid, &option.) );
        %let rc     = %sysfunc(close(&dsid) );
    %end;
        %else %let nobs=-1;

    &nobs
%mend;

%put NOBS: %get_nobs(sashelp.cars);

SAS Macros为您编写代码。您的尝试无效,因为他们试图在%put语句中执行非宏代码。

你可以做你正在尝试的事情,但是如何编写一个调用宏并返回值的函数。它涉及到上述方法要简单得多。