SAS - 如何从 SAS 宏返回值? [英] SAS - How to return a value from a SAS macro?

查看:18
本文介绍了SAS - 如何从 SAS 宏返回值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

%macro nobs(library_name, table_name);proc sql noprint;选择 nlobs 到 :nobs来自字典表其中 libname = UPCASE(&library_name)和 memname = UPCASE(&table_name);退出;*返回 nobs 宏变量;&nobs%修补;%let num_of_observations = %nobs('工作', '患者');

另外,我希望宏中使用的 &nobs 宏变量是该宏的本地变量,而不是全局变量.我该怎么做?

解决方案

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

<块引用>

我主要关心的是如何从宏中返回一个值.

我要在这里以重要的方式与 Dirk 争辩.他说:

<块引用><块引用>

SAS 宏插入代码.它永远不能返回值,尽管在某些情况下你可以模仿函数

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

然而,宏只能返回单个值如果它除了该值之外只有宏语句.这意味着,每一行都必须以 % 开头.不以 % 开头的任何内容都将被返回(并且某些以 % 开头的内容也可能被返回.

所以重要的问题是,我如何从宏中返回一个值.

<小时>

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

Jack Hamilton 的链接 论文 包含一个适合此处的示例.他驳回了这个例子,但这主要是因为他的论文是关于计数观察在 NOBS 错误的情况下 - 使用 WHERE 子句,或者在某些其他情况下,数据集已被修改而没有 NOBS 元数据更新了.

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

返回值的宏必须恰好有一个语句,该语句要么不是宏语法语句,要么将值返回到处理中的宏语法语句溪流.%sysfunc 是这样做的语句示例.%let%put%if 等是不返回任何内容的语法语句(本身);这样您就可以拥有任意数量的这些.

您还必须有一个语句可以在处理流中放置一个值:否则您将无法从宏中得到任何东西.

这是第 3 页末尾的 Jack 宏的精简版,经过简化以删除他所显示的错误 nlobsf:

 %宏检查;%let dsid = %sysfunc(open(sashelp.class, IS));%如果 &DSID = 0 %那么%put %sysfunc(sysmsg());%let nlobs = %sysfunc(attrn(&dsid, NLOBS));%put &nlobs;%let rc = %sysfunc(close(&dsid));%修补;

那个宏不是一个函数风格的宏.它不会向处理流返回任何内容!它对于查看日志很有用,但对于为您提供可以编程的值没有用.但是,对于函数样式宏来说,这是一个好的开始,因为您真正想要的是 &nlobs,对吧?

 %宏检查;%let dsid = %sysfunc(open(sashelp.class, IS));%如果 &DSID = 0 %那么%put %sysfunc(sysmsg());%let nlobs = %sysfunc(attrn(&dsid, NLOBS));&nlob%let rc = %sysfunc(close(&dsid));%修补;

现在这是一个函数样式的宏:它有一个不是宏语法语句的语句,&nlobs. 单独一行.

这实际上比你需要的一个语句还要多;还记得我说过 %sysfunc 向处理流返回一个值吗?您可以删除该语句的 %let 部分,留下

 %sysfunc(attrn(&dsid, NLOBS))

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

让我们乖乖地添加一些 %local 来让这个既美观又安全,并将数据集的名称作为参数,因为大自然厌恶没有参数的宏:

 %macro check(dsetname=);%local dsid nlobs rc;%let dsid = %sysfunc(open(&dsetname., IS));%如果 &DSID = 0 %那么%put %sysfunc(sysmsg());%let nlobs = %sysfunc(attrn(&dsid, NLOBS));&nlob%let rc = %sysfunc(close(&dsid));%修补;%let classobs= %check(dsetname=sashelp.class);%put &=classobs;

你有它:一个函数样式的宏,它使用 nlobs 函数来找出任何特定数据集中有多少行.

I would like to return a value from a SAS macro I created but I'm not sure how. The macro computes the number of observations in a dataset. I want the number of observations to be returned.

%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');

Also, I would like the &nobs macro variable that is used within the macro to be local to that macro and not global. How can I do that?

解决方案

I'll answer the core question Bambi asked in comments:

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

I'm going to quibble with Dirk here in an important way. He says:

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

I disagree. A SAS macro returns text that is inserted into the processing stream. Returns is absolutely an appropriate term for that. And when the text happens to be a single numeric, then it's fine to say that it returns a value.

However, the macro can only return a single value if it only has macro statements in addition to that value. Meaning, every line has to start with a %. Anything that doesn't start with % is going to be returned (and some things that do start with % might also be returned).

So the important question is, How do I return only a value from a macro.


In some cases, like this one, it's entirely possible with only macro code. In fact, in many cases this is technically possible - although in many cases it's more work than you should do.

Jack Hamilton's linked paper includes an example that's appropriate here. He dismisses this example, but that's largely because his paper is about counting observations in cases where NOBS is wrong - either with a WHERE clause, or in certain other cases where datasets have been modified without the NOBS metadata being updated.

In your case, you seem perfectly happy to trust NOBS - so this example will do.

A macro that returns a value must have exactly one statement that either is not a macro syntax statement, or is a macro syntax statement that returns a value into the processing stream. %sysfunc is an example of a statement that does so. Things like %let, %put, %if, etc. are syntax statements that don't return anything (by themselves); so you can have as many of those as you want.

You also have to have one statement that puts a value in the processing stream: otherwise you won't get anything out of your macro at all.

Here is a stripped down version of Jack's macro at the end of page 3, simplified to remove the nlobsf that he is showing is wrong:

 %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;

That macro is not a function style macro. It doesn't return anything to the processing stream! It's useful for looking at the log, but not useful for giving you a value you can program with. However, it's a good start for a function style macro, because what you really want is that &nlobs, right?

 %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;

Now this is a function style macro: it has one statement that is not a macro syntax statement, &nlobs. on a plain line all by itself.

It's actually more than you need by one statement; remember how I said that %sysfunc returns a value to the processing stream? You could remove the %let part of that statement, leaving you with

 %sysfunc(attrn(&dsid, NLOBS))

And then the value will be placed directly in the processing stream itself - allowing you to use it directly. Of course, it isn't as easy to debug if something goes wrong, but I'm sure you can work around that if you need to. Also note the absence of a semi-colon at the end of the statement - this is because semicolons aren't required for macro functions to execute, and we don't want to return any extraneous semicolons.

Let's be well behaved and add a few %locals to get this nice and safe, and make the name of the dataset a parameter, because nature abhors a macro without parameters:

 %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;

There you have it: a function style macro that uses the nlobs function to find out how many rows are in any particular dataset.

这篇关于SAS - 如何从 SAS 宏返回值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆