为什么直接运行时使用CALL EXECUTE运行宏错误? [英] Why does using CALL EXECUTE to run a macro error when running it directly works?

查看:12
本文介绍了为什么直接运行时使用CALL EXECUTE运行宏错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近继承了一个看起来像这样的 SAS 程序:

I recently inherited a SAS program that looks something like this:

%MACRO ComplicatedStuff( GroupId= );

    %LET FileId = %SYSFUNC( OPEN( Work.BigDataSet ) );

    %PUT    'Doing something really difficult with ' &GroupId.;

    %LET CloseRC = %SYSFUNC( CLOSE( &FileId. ) );

%MEND ComplicatedStuff;

%ComplicatedStuff(GroupId=ABC1);
%ComplicatedStuff(GroupId=DEF2);
%ComplicatedStuff(GroupId=3GHI);
%ComplicatedStuff(GroupId=J4KI);

作为一名多面手的程序员,我看到这个并认为我当然可以让它至少更动态一点".果然,我能够使用 CALL EXECUTE 开发出我认为的简单解决方案:

Being a multi-faceted programmer, I looked at this and thought "surely I can make this a least a little bit more dynamic". Sure enough, I was able to develop what I thought was a simple solution using CALL EXECUTE:

DATA Work.IDs;

    INPUT   ID      $4.
            ;

DATALINES;
ABC1
DEF2
3GHI
J4KI
RUN;

DATA Work.CommandDebug;
    SET Work.IDs;

    Command = CATS(
                '%ComplicatedStuff(GroupId=', ID, ');'
              );

    CALL EXECUTE( Command );

RUN;

我对这个解决方案很满意,直到需要将 ComplicatedStuff 生成的文件通过 FTP 传输到不同的服务器.我们的 SAS 服务器在 Unix 上运行,SAS 管理员为我们创建了一个有用的小宏来调用名为 %sas_sftp (因为有人告诉我,x 代码真的很丑).不幸的是,我无法发布 %sas_sftp 代码 - 它属于我的公司,我认为他们不想在 SO 上使用它.

I was happy with this solution until it came time to FTP the files generated by ComplicatedStuff to a different server. Our SAS server is running on Unix and the SAS admins created a helpful little macro for us to call named %sas_sftp (because, I've been told, the x code gets really ugly). Unfortunately, I cannot post the %sas_sftp code - it belongs to my company and I don't think they want it on SO.

我尝试调用 %sas_sftp 宏,就像我调用 %ComplicatedStuff 宏一样(都作为第二个 CALL EXECUTE 在相同的数据步骤,并作为第二个数据步骤),但只有第一个文件(大约 30 个)会到达目的地.当我查看日志时,看起来第二个宏在 ftp 完成之前开始执行(ftp 管道或其他任何东西在下一个 ftp 开始之前还没有被释放),所以随后的 ftp 只是默默地失败了由于资源不可用(我想).

I attempted to call the %sas_sftp macro just as I had called the %ComplicatedStuff macro (both as a second CALL EXECUTE within the same data step, and as a second data step), but only the first file (of about 30) would make it to the destination. When I looked at the log, it looked like the second macro started executing before the ftp had finished (the ftp pipe, or whatever it is, hadn't been released before the next ftp started), so the subsequent ftps were simply silently failing due to resource unavailability (I presume).

我认为 EXECUTE 基本上会将我的宏调用排队,然后执行它们,就好像它们按顺序位于代码中一样(就像它们最初一样) - 一次一个.显然还有其他事情正在发生,因为虽然上面的第一种方法没有问题,但我的动态解决方案失败了.我倾注了 CALL EXECUTE: How and WhySAS 文档,但我是恐怕我只是不明白他们在说什么.

I thought that the EXECUTE would basically queue up my macro calls and then execute them as if they were sequentially located in the code (as they originally were) - one at a time. Clearly something else is going on because, while the first approach above worked without issue, my dynamic solution failed. I poured over CALL EXECUTE: How and Why and the SAS documentation, but I'm afraid I just don't understand what they are talking about.

我最终确实找到了一个解决方法(或者更确切地说,一位同事找到了一个),我在下面发布了一个答案",但我真的希望有人解释 EXECUTE 函数及其工作原理.

I did eventually find a work around (or rather, a colleague found one) which I posted below as an "answer", but I'd really like someone to explain the EXECUTE function and how it works.

为什么我使用 CALL EXECUTE 的第一次尝试没有成功?

Why didn't my first attempt, using CALL EXECUTE, work?

推荐答案

CALL EXECUTE 的工作方式与您在社区 wiki 中的代码类似,除了一些与时间相关的特定问题.我遇到的最常见的问题是,当我在做一个包含定义宏变量的东西的宏时,例如该宏中的 PROC SQL select into 然后创建宏中使用的宏文本- 与您的答案没有什么不同.由于计时规则,直到 CALL EXECUTE 完成构建要执行的代码后才会执行,这意味着代码内部的值没有正确更改.

CALL EXECUTE works similarly to your code in the community wiki, except for some specific issues relating to timing. The most common issue I run into is when I'm doing a macro that includes something that defines a macro variable, such as a PROC SQL select into inside that macro which then creates macro text used in the macro - not dissimilar to your answer. Because of timing rules, that isn't executed until after the CALL EXECUTE finishes constructing the code to be executed, which means the value isn't changed properly inside the code.

这是一个例子.

%macro mymacro(age=0);
proc sql noprint;
select quote(name) into :namelist separated by ',' from sashelp.class where age=&age.;
quit;

data name_age;
set sashelp.class;
where name in (&namelist.);
run;
proc print data=name_age;
var name age;
run;
%mend mymacro;

proc sort data=sashelp.class out=class nodupkey;
by age;
run;

好的,现在我有一个控制数据集(class)和一个宏来运行它.这是调用执行.这不能正常工作;第一次运行时,您将收到有关 &namelist 未定义的消息,第二次和以后您将收到所有 age=16(最后一个年龄),因为这是宏变量的定义.

OK, now I have a control dataset (class) and a macro to run off it. Here is the call execute. This does not work properly; the first time it runs you will get messages about &namelist being undefined, the second and future times you will get all age=16 (the last age) since that is what the macro variable is defined as.

data _null_;
set class;
exec_val = cats('%mymacro(age=',age,')');
call execute(exec_val);
run;

这里是sql宏调用.这按预期工作.

Here is the sql macro call. This works as expected.

proc sql noprint;
select cats('%mymacro(age=',age,')') into :calllist separated by ' '
    from class;
quit;   
&calllist;

我发现调用 execute 不如 PROC SQL 宏列表解决方案对数据生成代码有用,除非在数据步骤中构造代码更容易并且我没有做任何导致计时问题的事情.

I don't find call execute to be as useful as the PROC SQL macro list solution to data generated code, except when it's easier to construct the code in a data step and I'm not doing anything that causes timing issues.

这篇关于为什么直接运行时使用CALL EXECUTE运行宏错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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