【问题标题】:Why does my macro behave differently with call execute()?为什么我的宏在调用 execute() 时表现不同?
【发布时间】:2014-12-09 09:57:22
【问题描述】:

使用 SAS,我经常想对数据集的每一行执行一个操作。为此,我使用了在教程中找到的命令:call execute()。由于我对 SAS 环境不是很熟悉,所以我倾向于使用宏函数来做任何我不知道如何执行的事情,并使用call execute() 执行它们。 但是,我很难理解宏语言在 SAS 中是如何工作的。我知道首先解析所有宏引用,它提供了一个基本 SAS 代码,然后执行(或者我已经错了吗?)。但我不明白它如何适用于call execute()。 让我们考虑以下代码:

%macro prog1;    /* %prog1 defines a macrovariable mv1 */
%global mv1;
data _null_;
call symputx("mv1","plop");
run;
%mend;

%macro prog2(var);    /* prog2 puts it on the log */
%put PUT &var;
%mend;

%macro prog_glob;    /* prog_glob executes prog 1 then prog2 */
%prog1;
%prog2(&mv1);
%mend;

我知道这里不需要三个宏,但这是我的真实代码的最小版本,它具有这种结构。

现在如果我执行prog_glob

%prog_glob;

正如预期的那样,我在日志上得到了PUT plop。 但是如果我将它与call execute() 一起使用(即使这里不需要循环):

data _null_;
mac=%NRSTR("%prog_glob");
call execute(mac);
run;

我只得到PUT。 没有错误提示未定义宏变量,因此 %global 语句有效。但不知何故,prog2 是在prog1 基础部分之前执行的(至少我是这么认为的),而mv1 尚未定义。

我的问题是:

  • 我的解释正确吗?
  • 为什么我使用call execute时结果会改变?
  • 根据前面的问题答案,我应该如何修复它或者是否有更方便的方法来循环遍历列值?

编辑: 我的原始代码打算重命名几个表的变量,这些表我已在数据集中列出。对于每个列出的表,我希望执行以下算法:

  • prog1 : 在宏变量中存储一个包含所有变量的列表(这是我定义 mv 等效项的地方)
  • prog2 : 为这些变量名称添加通用后缀

可能有更聪明的方法来做到这一点。同样,我对 SAS 不太熟悉,而且我倾向于过度使用宏。如果你想告诉我一个更好的方法来做到这一点,我很乐意聊天,但我不希望你们重写我所有的代码,所以call execute 的替代品足以让我感激不尽! :)

【问题讨论】:

标签: sas call sas-macro


【解决方案1】:

让我们看一下文档 http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#a000543697.htm

如果 EXECUTE 例程参数是宏调用或解析为一个,则宏立即执行。但是,由 EXECUTE 例程生成的任何 SAS 语句直到通过步骤边界后才会执行

注意:因为宏引用会立即执行,并且 SAS 语句在步边界之后才会执行,因此您不能使用 CALL EXECUTE 调用包含宏变量引用的宏,这些宏变量是由该宏中的 CALL SYMPUT 创建的。例如,请参阅与宏工具的接口。

这意味着,如果你通过调用执行来调用它:

  1. 宏语句会立即执行——它们是:

    1.1。首先在 %prog1: %global mv1; - 所以 mv1 已定义但为空,没有明显...警告

    1.2。来自 %prog1 的 SAS 语句仍被延迟

  2. 现在 %prog2 - 这是唯一的宏语句 %PUT,它放置(仍然为空)&mv1 变量。您在日志中看到的内容
  3. 现在所有立即执行的操作都已完成。包含调用执行的数据步骤结束。
  4. 现在正在执行从调用执行延迟的 SAS 语句:

    4.1。 prog1 的数据集设置 mv1 的值。

仅此而已:-)

编辑:关于您的编辑:尝试查看此http://support.sas.com/kb/48/674.html

【讨论】:

  • 谢谢,我现在明白了。但是,我无法删除原始代码中的 call symputxequivalent。有没有您建议替换 call execute 的命令?
  • 取决于你为什么需要调用执行?宏调用是动态的吗?是否有一些调用顺序?
  • 我编辑了我的问题以解释我想要做什么。
  • 事实上,我使用的方式与您的新链接建议的方式完全相同!但是宏变量是用proc sql 定义的,所以它与我的示例中的call symputx 相同。
【解决方案2】:
data _null_;
mac='%nrstr(%prog_glob)';
call execute(mac);
run;

或者,更清楚地说,正如您在文档中看到的那样......

data _null_;
call execute('%nrstr(%prog_glob)');
run;

%let prog=%nrstr(%prog_glob);

data _null_;
mac="&prog.";
call execute(mac);
run;

或者,我不会真的推荐这个,但你也可以手动连接宏引号

data _null_;
mac=cats('01'x,'%prog_glob','02'x);
call execute(mac);
run;

您运行它的方式,宏语句在运行时执行,数据步骤在调用数据步骤完成后执行。如文档所述,您没有在此上下文中正确使用 %NRSTR。您需要将宏以及引用作为文本传递给调用例程。

【讨论】:

    猜你喜欢
    • 2015-05-09
    • 1970-01-01
    • 2022-11-27
    • 2020-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多