我想从我创建的 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/