从sas数据步骤dynamic调用macros

当作为SAS程序运行时,此代码执行得很好:

%MyMacro(foo_val, bar_val, bat_val);

我创build了一个表,使用:

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

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

下面的代码似乎只传递string值titleweightresponse (而不是数据值foo1等)到我的macros(testing调用%put命令):

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

如何在analyses表的每个logging中调用macros一次,同时将数据值作为parameter passing给macros? 目的是为了进行大量的分析,所以解决scheme必须适当地扩展到analyses表中更多的logging。

这部分取决于你的macros在做什么。 如果我们假设你的macros正在做一些有意在数据步之外运行的东西(即它不只是分配一个数据步variables),那么你有几个select。

  • 呼叫执行
  • PROC SQL:SELECT INTOmacrosvariables
  • 将macros调用写入%INCLUDE文件
  • DOSUBL

CALL EXECUTE已经被解释了,对于某些情况是一个不错的select。 但是,它有一些缺点,特别是对于macros观时机,在某些情况下需要特别注意保护 – 特别是在macros内部创buildmacrosvariables时。 Quentin在他的评论中展示了一种方法来解决这个问题(在调用中添加%NRSTR ),但是我发现我更喜欢只使用CALL EXECUTE,而在其他方法上有优势时 – 特别是如果我想使用SAS数据步骤技术(例如FIRST或LAST,或者某种forms的循环)来创build我的macros调用,或者当我必须在数据步骤中执行某些操作时,可以避免再次读取文件的开销。 如果我只是像上面一样写数据步骤 – 数据,设置,执行,运行 – 我不会使用它。


PROC SQL SELECT INTO通常用于列表处理(主要是这是什么)。 在做一些不太复杂的事情时,我喜欢SQL的简单性, 例如,您可以使用DISTINCT轻松获得每个macros调用的一个版本,而不必显式编写一个proc sort nodupkey或使用first / last处理。 它还具有debugging的优点,你可以把所有的macros调用写到你的结果窗口(如果你不添加noprint ),如果我想知道为什么它比日志更容易阅读我的电话没有得到正确生成(并没有采取任何额外的PUT语句)。

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

这很容易运行,并没有时间问题(因为你只是写一堆macros调用)。

这种方法的主要缺点是在macrosvariables中最多有64个字符,所以如果你写了大量的这些字符,你就会遇到这个问题。 在这种情况下,使用CALL EXECUTE%INCLUDE文件。


%INCLUDE文件在很大程度上是有用的,或者当调用超过字符限制时replace为SELECT INTO ,或者如果你觉得有一个文本文件可以查看你的调用(如果你正在批处理模式下运行这个文件) ,这可能比日志或列表输出更容易和/或parsing)。 您只需将您的呼叫写入文件,然后%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更接近你期待的直观性。 文档页面真的是这个工作方式不同的最好例子。 基本上,它通过让每个单独的调用看起来导入和从调用环境中导出macrosvariables来修复计时问题,这意味着DOSUBL每次迭代都在明显的时间运行,而在CALL EXECUTE ,一切运行在一堆,macros环境是“固定的”(即,任%NRSTRvariables的引用在运行时都是固定的,除非你用%NRSTR转义它)。


还有一件值得一提的事是RUN_MACRO ,它是RUN_MACRO语言的一部分。 这样可以完全运行一个macros并将其内容导回到数据步骤 ,在某些情况下这是一个有趣的选项(例如,可以围绕一个PROC SQL打包调用,select一些事物,然后导入到数据集作为一个variables,所有在一个datastep)。 如果你这样做是为了调用一个macros来分配一个数据步variables,而不是运行一个不需要导入到数据步中的事务的进程,但是这是值得考虑的确实希望这些数据全部返回到调用该进程的数据集中。

你可以使用CALL EXECUTE:

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

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

数据:

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

运行macros的代码:

 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;