这部分取决于您的宏正在做什么。如果我们假设您的宏正在执行旨在在数据步骤之外运行的操作(即,它不仅仅是分配数据步骤变量),那么您有多种选择。
CALL EXECUTE 已经解释过了,在某些情况下是一个不错的选择。然而,它有一些缺点,特别是在宏定时方面,在某些情况下需要格外小心来保护 - 特别是当您在宏中创建宏变量时。 Quentin 在他的 cmets 中展示了一种解决此问题的方法(将 %NRSTR 添加到调用中),但我发现我更喜欢仅在使用 CALL EXECUTE 比其他方法有优势时才使用 - 特别是,如果我想使用 SAS 数据步骤技术(例如 FIRST 或 LAST,或某种形式的循环)来创建我的宏调用,或者当我必须在数据步骤中做一些事情并且可以避免再次读取文件的开销时.如果我只是在写一个像你上面那样的数据步骤——数据、设置、调用执行、运行——我不会使用它。
PROC SQL SELECT INTO 通常是我用于列表处理的东西(这在很大程度上就是这样)。在做不太复杂的事情时,我更喜欢 SQL 的简单性。例如,您可以使用DISTINCT 轻松获得每个宏调用的一个版本,而无需显式编写proc sort nodupkey 或使用第一个/最后一个处理。它还具有调试的优势,您可以将所有宏调用写入结果窗口(如果您不添加noprint),如果我尝试,这比我的日志更容易阅读看看为什么我的调用没有正确生成(并且不需要任何额外的 PUT 语句)。
proc sql;
select catx(',','%macro(',arg1,arg2,arg3)||')'
into :mvarlist separated by ' '
from dataset;
quit;
&mvarlist.
它们的运行非常简单,并且没有时间问题(因为您只是在编写一堆宏调用)。
这种方法的主要缺点是宏变量中最多有 64k 个字符,因此如果您要编写大量这些字符,就会遇到这种情况。在这种情况下,请使用 CALL EXECUTE 或 %INCLUDE 文件。
%INCLUDE 文件在调用超过字符限制时作为SELECT INTO 的替换非常有用,或者如果您发现有一个文本文件来查看您的调用很有用(如果您正在运行此例如,在批处理模式下,这可能比日志或列表输出更容易获取和/或解析)。您只需将调用写入文件,然后 %INCLUDE 该文件即可。
filename myfile temp; *or a real file if you want to look at it.;
data _null_;
set dataset;
file myfile;
length str $200;
str=catx(',','%macro(',arg1,arg2,arg3)||')';
put str;
run;
%include myfile;
我真的不再使用这种技术了,但它是一种常见的技术,特别是老 SAS 程序员使用的技术,非常值得了解。
DOSUBL 是一种相对较新的方法,在某种程度上可以用来替代CALL EXECUTE,因为它的默认行为通常比CALL EXECUTE 更接近您直观的预期。文档页面确实是如何以不同方式工作的最佳示例;基本上,它通过让每个单独的调用看起来从调用环境导入和导出宏变量来解决时间问题,这意味着DOSUBL 的每次迭代都在不同的时间运行,而CALL EXECUTE 的所有内容都在一个运行一堆并且宏环境是“固定的”(即,对宏变量的任何引用在运行时都是固定的,除非你用%NRSTR 将其转义)。
还有一点值得一提的是RUN_MACRO,它是FCMP 语言的一部分。这允许您完全运行宏并将其内容导入回数据步骤,这在某些情况下是一个有趣的选项(例如,您可以围绕选择计数的 PROC SQL 包装调用的东西,然后将其作为变量导入数据集,所有这些都在一个数据步中)。如果您这样做是为了调用宏来分配数据步骤变量,而不是运行一个执行不需要导入数据步骤的事情的进程,那么它是适用的,但如果您这样做是值得考虑的确实希望将这些数据全部返回到调用该过程的数据集中。