全部版块 我的主页
论坛 数据科学与人工智能 数据分析与数据科学 SAS专版
35016 49
2013-04-28

(注:由于有部分代码和啰嗦的程序解释,所以导致帖子很长,不得不分两层贴出)


关于 CALL EXECUTE()

CALL EXECUTE() 的功能是"Resolves its argument and executes the resolved value at the next step boundary"。


CALL EXECUTE()的参数是字符串,在执行时,SAS会把这个字符串送到宏处理器中。宏处理器如遇到宏的语句,如%let%put等,会直接执行;如遇到SAS语句,这些SAS语句会被排到CALL EXECUTE()所在DATA步之后等待运行。


如果使用熟练,CALL EXECUTE()实在是称得上一件趁手的兵器,值得收在SAS武器库里备用。当然,这会需要多加练习和揣摩。希望下面的几个例子能够帮助大家理解CALL EXECUTE()的执行机制,以避免掉入陷阱。或者即便是使用CALL EXECUTE()时遇到了血红色的“ERROR”,也能很快的找到错误的原因。话说回来,能够给出错误或警告信息的陷阱还算是“好”的陷阱,有些陷阱是不会在log窗口留下任何痕迹的。


CALL EXECUTE() 能做什么

很多情况下,CALL EXECUTE()可以实现宏的效果。使用宏,我们需要“定义宏”+“调用宏”;使用CALL EXECUTE(),我们可以在DATA步的执行过程中,根据变量的值生成不同的代码,而这些代码会在DATA步执行完后自动运行。


比如,下面的例子可以求出数据集中数值型变量的描述性统计和字符型变量各个值的频数:

复制代码


如果CALL EXECUTE()的参数值只包含SAS语句的话,理解起来是比较简单和直观的。但如果其参数值包含宏的因素(宏变量,宏语句,宏的调用)时,理解起来就可能比较困难,难点就在于究竟宏变量的值是什么时候解析的,以及宏语句是什么时候被执行的。



CALL EXECUTE() 中的宏变量


下面这个例子可以用来说明CALL EXECUTE()中宏变量的解析情况:


复制代码


程序解释:


数据集TEST中变量X的值



第一个CALL EXECUTE()所产生的数据集中 X的值为’bad’。这是因为当宏的调用放到双引号中时,宏的执行是在DATA步的编译阶段进行的。而宏执行的结果(’data test’ 代码)再放到一对双引号之间作为CALL EXECUTE() 的参数。这就相当于:


call execute("data test; x='&aa'; y=symget('aa'); put x= y=; run;");



这时虽然宏变量aa的引用用两边是单引号(’&aa’),但是整个字符串却处在双引号里面,因而单引号会被当成普通字符,并不会影响到&aa的解析为宏参数的值--bad。这样DATA步编译完后,第一个CALL EXECUTE() 就会是:


call execute("data test; x='bad'; y=symget('aa'); put x= y=; run;");




第二个CALL EXECUTE()所产生的数据集X的值为'&aa'。 这是因为宏的调用位于单引号中,所以DATA步编译阶段宏不会执行。而在DATA步的执行阶段,CALL EXECUTE() 中调用的宏会被执行,产生的SAS代码会去排队(在input stack中)等待运行。这时&aa两边的单引号就会发挥其“屏蔽宏变量解析”的功能,因此X的值即为'&aa'.


数据集TEST中变量Y的值:'Good'

因为SYMGET()函数的参数只是宏变量的名字'aa'而不用符号’&’,因此在DATA _NULL_步的编译和执行过程中都不会试图去解析宏变量aa的值。而等DATA _NULL_执行完毕,CALL EXECUTE()所产生的代码执行时,SYMGET()才去尝试找aa的值。需要注意的是,此时的代码并不在宏的执行环境里,而是在open code。所以SYMGET() 返回的aa的值不是%test宏的参数值,而是global symbol table中的值—Good

另外,如果希望SYMGET()函数返回宏%test所指定的参数值,可以用:


call execute('%nrstr(%test(bad))');



a. 单引号的使用可以跳过所在DATA步的编译阶段;

b. %NRSTR()的使用可以使宏的执行跳过所在DATA步的执行阶段;

这就相当于DATA步执行完毕后直接调用宏:%test(bad)

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

全部回复
2013-4-28 20:52:20
CALL EXECUTE() 中的宏语句

如果CALL EXECUTR()的参数中有宏语句,那么宏语句在何时执行会有三种情况:

1.        如果宏语句在双引号中并没有使用%NRSTR(),宏语句会在DATA步编译阶段执行;
2.        如果宏语句在单引号中,或者在双引号中并使用了%NRSTR(),宏语句会在DATA步执行阶段执行;
3.        如果宏语句在单引号中,并且使用了%NRSTR(),则宏语句会在DATA步执行完之后执行。
复制代码

CALL EXECUTE() 中宏的调用

宏的帮助文档里说:“Argument within single quotation marks resolves during program execution. Argument within double quotation marks resolves while the DATA step is being constructed.”。

因此,如果我们需要在CALL EXECUTE()中调用宏,并且需要用数据集中变量的值作为宏参数的话,则应该把宏的调用放到单引号里。

下面这个例子通过CALL EXECUTE()对两个宏的调用来演示不同情况下宏的执行情况。
复制代码

后两个调用是在data步运行时才会产生宏调用语句并执行宏,所以比较直观,容易理解。
而前两个调用中宏是DATA步的编译阶段就已经执行完毕,所产生的SAS代码继续放到CALL EXECUTE()中;等到DATA步执行时,CALL EXECUTE()中生成的代码会等DATA步执行完后依次执行。前两个调用相当于下面的代码 (其中的%PUT语句会在DATA步编译时执行):

复制代码

而第一个调用(invoke 1)所产生的DATA步的代码会变为: dataa1; num=1; x="||strip(age)||"; run;。这里的||strip(age)||是一个字符串,而并不会被SAS理解成两个连接符中的一个STRIP()函数。(这是因为双引号之间如果有两个连续的双引号,则执行后会变为一个双引号,因此所产生的代码中||strip(age)||左右会各有一个双引号,从而会被认为一个字符串。)



第二个调用(invoke 2)则有所不同,||strip(age)||前后只有一个双引号,使得||strip(age)||被解放出来而继续发挥连接符和函数的功能,并且age也会作为一个变量,而不是像第一个调用中的普通字符了。






二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2013-4-28 21:01:21
论坛的编辑器实在是不敢恭维啊
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2013-4-28 22:16:04
pobel 发表于 2013-4-28 21:01
论坛的编辑器实在是不敢恭维啊
嗯,下次我跟论坛的管理员反映下这个问题。
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2013-4-28 22:17:25
pobel, 真希望你能写本书,专门解读SAS机制和语句。
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2013-4-29 03:26:53
thanks, very helpful
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

点击查看更多内容…
相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群