SAS - 如何从 SAS 宏返回值?

标签 sas

我想从我创建的 SAS 宏返回一个值,但我不确定如何。该宏计算数据集中的观察数。我想要返回的观察次数。

%macro nobs(library_name, table_name);
  proc sql noprint;
    select nlobs into :nobs
    from dictionary.tables
    where libname = UPCASE(&library_name)
      and memname = UPCASE(&table_name);
  quit;

  *return nobs macro variable;
  &nobs
%mend;

%let num_of_observations = %nobs('work', 'patients');

另外,我想要&nobs在宏中使用的宏变量是该宏的局部变量,而不是全局变量。我怎样才能做到这一点?

最佳答案

我将回答 Bambi 在评论中提出的核心问题:

My main concern here is how to return a value from a macro.



我将在这里以一种重要的方式与德克争论。他说:

A SAS macro inserts code. It can never return a value, though in some cases you can mimic functions



我不同意。 SAS 宏返回插入到处理流中的文本。退货绝对是一个合适的术语。当文本恰好是单个数字时,可以说它返回一个值。

但是,如果宏除了该值之外只有宏语句,则它只能返回单个值。意思是,每一行都必须以 % 开头。 .任何不以 % 开头的内容将要返回(并且某些以 % 开头的内容也可能会返回)。

所以重要的问题是,我如何返回 只有来自宏的值。

在某些情况下,像这种情况,完全可以只用宏代码。事实上,在许多情况下,这在技术上是可行的——尽管在许多情况下,这比您应该做的工作要多。

jack 汉密尔顿的链接 paper包括一个适合此处的示例。他驳回了这个例子,但这主要是因为他的论文是关于在 NOBS 错误的情况下计算观察结果 - 无论是使用 WHERE 子句,还是在没有更新 NOBS 元数据的情况下修改数据集的某些其他情况。

在您的情况下,您似乎非常乐意信任 NOBS - 所以这个例子就行了。

返回值的宏必须恰好有一个语句,该语句不是宏语法语句,或者是将值返回到处理流中的宏语法语句。 %sysfunc是这样做的语句的示例。诸如 %let 之类的东西, %put , %if等是不返回任何内容(本身)的语法语句;所以你可以拥有尽可能多的那些。

您还必须有一个将值放入处理流的语句:否则您将根本无法从宏中获得任何信息。

这是第 3 页末尾 Jack 宏的精简版,简化为删除了 nlobsf他展示的是错误的:
 %macro check;

   %let dsid = %sysfunc(open(sashelp.class, IS));
   %if &DSID = 0 %then
   %put %sysfunc(sysmsg());

   %let nlobs = %sysfunc(attrn(&dsid, NLOBS));

   %put &nlobs;

   %let rc = %sysfunc(close(&dsid));

 %mend;

该宏不是函数风格的宏。它不会向处理流返回任何内容!它对于查看日志很有用,但对于为您提供可用于编程的值没有用处。然而,对于函数风格的宏来说,这是一个好的开始,因为你真正想要的是 &nlobs , 对?
 %macro check;

   %let dsid = %sysfunc(open(sashelp.class, IS));
   %if &DSID = 0 %then
   %put %sysfunc(sysmsg());

   %let nlobs = %sysfunc(attrn(&dsid, NLOBS));

   &nlobs

   %let rc = %sysfunc(close(&dsid));

 %mend;

现在这是一个函数风格的宏:它有一个不是宏语法语句的语句,&nlobs.在一条简单的线上。

它实际上比你需要的更多;记得我是怎么说的%sysfunc向处理流返回一个值?您可以删除 %let该声明的一部分,给你留下
 %sysfunc(attrn(&dsid, NLOBS))

然后该值将直接放置在处理流本身中 - 允许您直接使用它。当然,如果出现问题,调试并不容易,但我相信如果需要,您可以解决这个问题。还要注意语句末尾没有分号——这是因为宏函数不需要分号来执行,而且我们不想返回任何无关的分号。

咱们乖乖加几条%local s 以获得这个好和安全,并使数据集的名称成为参数,因为大自然憎恶没有参数的宏:
 %macro check(dsetname=);

   %local dsid nlobs rc;

   %let dsid = %sysfunc(open(&dsetname., IS));
   %if &DSID = 0 %then
   %put %sysfunc(sysmsg());

   %let nlobs = %sysfunc(attrn(&dsid, NLOBS));

   &nlobs

   %let rc = %sysfunc(close(&dsid));

 %mend;

 %let classobs= %check(dsetname=sashelp.class);

 %put &=classobs;

你有它:一个使用 nlobs 的函数风格的宏函数来找出任何特定数据集中有多少行。

关于SAS - 如何从 SAS 宏返回值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33817518/

相关文章:

sas - 从具有长名称的 Excel 工作表中检索数据 - SAS

sas - ODS Excel/Proc 报告 - 没有自动换行/合并单元格?

db2 - 两个值相减时 SAS 得到错误结果

SAS:将分位数分配给宏变量

date - SAS。根据文档,为什么 "Jan 11 2002"== "88399"?

java - SAS 安装因未找到 libXext 而失败

hadoop - SAS Hive (Hadoop) 中是否有 Contains 函数?

sas - 从SAS中的字符串中删除单引号

macros - 在设定的时间间隔后,在 SAS 宏超时中执行一个步骤

sas - 跨多个数据步骤维护 ID 值