从sas数据步骤动态调用宏

时间:2014-08-28 09:55:49

标签: sas sas-macro

当作为SAS程序运行时,此代码执行正常:

%MyMacro(foo_val, bar_val, bat_val);

我使用以下方法创建了一个表:

DATA analyses;
   input title : $32. weight : $32. response : $32.;
   datalines;
foo1 bar1 bat1
foo2 bar2 bat2
;

我想对MyMacro表的每一行执行一次analyses

以下代码似乎只将字符串值titleweightresponse(而不是数据值foo1等)传递给我的宏(使用调用%put命令:

DATA _NULL_ ;
    set analyses;
    %MyMacro(title, weight, response);

RUN;

如何将analyses表的每个记录调用一次宏,同时将数据值作为参数传递给宏?目的是为了进行大量分析而实际执行此操作,因此解决方案必须适当地扩展到analyses表中的更多记录。

3 个答案:

答案 0 :(得分:9)

这部分取决于你的宏在做什么。如果我们假设您的宏正在执行一些旨在在数据步骤之外运行的东西(即,它不只是分配数据步骤变量),那么您有几个选项。

已经解释了CALL EXECUTE,对于某些情况来说这是一个不错的选择。然而,它有一些缺点,特别是在宏时序方面,在某些情况下需要额外注意保护 - 特别是当你在宏中创建宏变量时。 Quentin在他的评论中展示了一种解决这个问题的方法(在呼叫中添加%NRSTR),但我发现我更喜欢只使用CALL EXECUTE,这样做比其他方法更有优势 - 特别是,如果我想在创建宏调用时使用SAS数据步骤技术(例如FIRST或LAST,或某种形式的循环),或者当我必须在数据步骤中执行操作时,可以避免开销另一次读取文件。如果我只是像上面那样写一个数据步骤 - 数据,设置,调用执行,运行 - 我不会使用它。


PROC SQL SELECT INTO通常是我用于列表处理的(这主要是这个)。在做一些不太复杂的事情时,我更喜欢SQL的简单性;例如,您可以使用DISTINCT轻松获取每个宏调用的一个版本,而无需显式编写proc sort nodupkey或使用第一个/最后一个处理。它还具有调试的优势,您可以将所有宏调用写入结果窗口(如果您不添加noprint),如果我和我,这比我的日志更容易阅读#39;我试图了解为什么我的电话没有正确生成(并且没有采取任何额外的PUT语句)。

proc sql;
  select catx(',','%macro(',arg1,arg2,arg3)||')' 
    into :mvarlist separated by ' '
    from dataset;
quit;

&mvarlist.

它非常简单地运行它们,没有时间问题(因为你只是写了一堆宏调用)。

这种方法的主要缺点是在宏变量中最多有64k个字符,因此如果您正在编写大量这些字符,那么您将遇到这个问题。在这种情况下,请使用CALL EXECUTE%INCLUDE个文件。


当呼叫超过字符数限制时,

%INCLUDE文件可以替代SELECT INTO,或者如果您发现通过调用查看文本文件很有用(如果您和#39;例如,在批处理模式下重新运行它,这可能比日志或列表输出更容易获得和/或解析。您只需将呼叫写入文件,然后%INCLUDE该文件。

filename myfile temp; *or a real file if you want to look at it.;
data _null_;
 set dataset;
 file myfile;
 put @1 catx(',','%macro(',arg1,arg2,arg3)||')';
run;

%include myfile;

我不再使用这么多了,但它是一种常用的技术,特别是旧的SAS程序员使用它很有用。


DOSUBL是一种相对较新的方法,在某种程度上可用于替换CALL EXECUTE,因为其默认行为通常比CALL EXECUTE'更接近您的预期。秒。 doc页面确实是最好的例子,说明它的工作方式不同;基本上,它通过让每个单独的调用看起来导入并将宏变量从/向调用环境导出来修复计时问题,这意味着DOSUBL的每次迭代都在与CALL EXECUTE不同的时间运行是一堆运行,宏环境是固定的#39; (也就是说,对宏变量的任何引用都是在运行时修复的,除非你用%NRSTR混乱地转义它。)


值得一提的另一件事是RUN_MACROFCMP语言的一部分。这允许您完全运行宏并将其内容导回到数据步骤,这在某些情况下是一个有趣的选项(例如,您可以围绕选择计数的PROC SQL进行调用的东西,然后将其作为变量导入数据集,所有这些都在一个datastep中。如果您是为了调用宏来分配数据步骤变量而不是运行不需要导入数据步骤的过程,那么它是适用的但是,如果您确实希望在调用该流程的数据集中返回所有数据,那么这是值得考虑的事情。

答案 1 :(得分:7)

您可以使用CALL EXECUTE:

data _null_;
  set analyses;
  call execute('%nrstr(%MyMacro('||title||','||weight||','||response||'))');
run;

答案 2 :(得分:0)

您可以将变量值放入macrovariables中,然后使用macrovariables作为参数多次调用%MyMacro(数据集中的obs数):

数据:

DATA analyses;
   input title : $32. weight : $32. response : $32.;
   datalines;
foo1 bar1 bat1
foo2 bar2 bat2
;
run;

运行宏的代码:

data _NULL_;
    set analyses end=fine;
    call symput("ARGUMENT"||compress(_N_),catx(",",title,weight,response));
    if fine then call symput("NLOOPS",compress(_N_));
run;
%*PUT &ARGUMENT1;
%*PUT &ARGUMENT2;

%MACRO MAIN;
%DO L=1 %TO &NLOOPS;
    %MyMacro(&&ARGUMENT&L);
%END;
%MEND;
%MAIN;