楼主: pobel
29137 47

[学习分享] 关于CALL EXECUTE()   [推广有奖]

院士

14%

还不是VIP/贵宾

-

威望
2
论坛币
14673 个
通用积分
3462.8973
学术水平
932 点
热心指数
930 点
信用等级
730 点
经验
113854 点
帖子
1287
精华
4
在线时间
3645 小时
注册时间
2008-12-10
最后登录
2024-2-28

初级热心勋章 中级热心勋章 初级信用勋章 初级学术勋章 中级信用勋章 中级学术勋章 高级热心勋章 高级学术勋章

楼主
pobel 在职认证  发表于 2013-4-28 20:07:25 |只看作者 |坛友微信交流群|倒序 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

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


关于 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步执行完后自动运行。


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

  1. data _null_;
  2.     set sashelp.vcolumn;
  3.         where libname="SASHELP" and memname="CLASS";

  4.         *** Get Frequency table for character var;
  5.         if type="char" then
  6.                        call execute("proc freq data=sashelp.class;
  7.                                         table "||strip(name)||"/out=freq_"||strip(name)||";
  8.                                      run;"
  9.                                            );

  10.         *** Get descriptive statistics for numeric var;
  11.         else if type="num" then
  12.                      call execute("proc means data=sashelp.class;
  13.                                         var "||strip(name)||";
  14.                                          output out=stat_"||strip(name)||";
  15.                                      run;"
  16.                                         );
  17. run;
复制代码


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



CALL EXECUTE() 中的宏变量


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


  1. %macro test(aa);
  2.      data test;
  3.              x='&aa';
  4.              y=symget('aa');
  5.                  put x= y=;
  6.          run;
  7. %mend;

  8. %let aa=Good;

  9. data _null_;
  10.     *** Double quotation;
  11.     call execute("%test(bad)");

  12.     *** Single quotation;
  13.     call execute('%test(bad)');
  14. run;
复制代码


程序解释:


数据集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)

二维码

扫码加我 拉你入群

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

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

关键词:EXECUTE Cute call cut ECU 武器库 处理器 字符串 程序

已有 13 人评分经验 论坛币 学术水平 热心指数 信用等级 收起 理由
wps930720 + 1 + 1 + 1 精彩帖子
bitcoin + 1 + 1 + 1 精彩帖子
6皮皮9 + 1 + 1 + 1 精彩帖子
intheangel + 60 + 3 + 3 + 3 精彩帖子
Tigflanker + 1 + 1 + 1 还没看就赶紧先把分加上!本地收藏!
ariman911 + 1 + 1 + 1 精彩帖子
boe + 1 + 1 + 1 精彩帖子
jingju11 + 5 + 5 + 5 精彩帖子
liujianfang + 100 奖励积极上传好的资料
Imasasor + 4 精彩帖子

总评分: 经验 + 360  论坛币 + 200  学术水平 + 29  热心指数 + 29  信用等级 + 29   查看全部评分

本帖被以下文库推荐

和谐拯救危机
沙发
pobel 在职认证  发表于 2013-4-28 20:52:20 |只看作者 |坛友微信交流群
CALL EXECUTE() 中的宏语句

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

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

  2. data _null_;
  3.   time_before=time();
  4.   put "-Time Before CALL EXECUTE:" time_before time12.3;

  5.   call symput("value","Hehe");

  6.    *** During DATA step Compile phase;
  7.    call execute("%put ;%put ---1  During compile: &value -- %sysfunc(putn(%sysfunc(time()),time12.3)); %put ;");

  8.    *** During DATA step Execution phase;
  9.    call execute('%put ;%put ---2.1 During execution: &value -- %sysfunc(putn(%sysfunc(time()),time12.3)); %put ;');
  10.    call execute("%nrstr(%put ;%put ---2.2 During execution: &value -- %sysfunc(putn(%sysfunc(time()),time12.3)); %put ;)");

  11.    *** After DATA step Execution;
  12.    call execute('%nrstr(%put ;%put ---3 After execution: &value -- %sysfunc(putn(%sysfunc(time()),time12.3));)');

  13.   call symput("value","Heihei");

  14.   time_after=time();
  15.   put "-Time After CALL EXECUTE:" time_after= time12.3;
  16. run;
复制代码

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()对两个宏的调用来演示不同情况下宏的执行情况。
  1. %macro test(num, mvar);
  2.    %put -----parameter value: &num &mvar;
  3.    data a#
  4.        num=#
  5.        x="&mvar";
  6.    run;
  7. %mend;

  8. %macro test1(num,mvar);
  9.    %put -----parameter value: &num &mvar;
  10.    data a a#
  11.        num=#
  12.        x=&mvar;
  13.    run;
  14. %mend;

  15. options mprint;

  16. data _null_;
  17.     set sashelp.class(obs=1);

  18.         *** invoke 1: Call %test in double quotation;
  19.         call execute("%test(1,"||strip(age)||")");

  20.         *** invoke 2: Call %test1 in double quotation;
  21.         call execute("%test1(2,"||strip(age)||")");

  22.         *** invoke 3: Call %test in single quotation;
  23.         call execute('%test(3,'||strip(age)||')');

  24.         *** invoke 4: Call %test1 in single quotation;
  25.         call execute('%test1(4,'||strip(age)||')');
  26. run;
复制代码

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

  1. data _null_;
  2.    set sashelp.class(obs=1);
  3.     *** invoke 1: Call %test in double quotation;
  4.         call execute("
  5.                   %put -----parameter value: 1 "||strip(age)||";
  6.                   data a1; num=1; x=""||strip(age)||""; run;
  7.                   ");

  8.         *** invoke 2: Call %test1 in double quotation;
  9.         call execute("
  10.                   %put -----parameter value: 2 "||strip(age)||";
  11.                   data a2; num=2; x="||strip(age)||"; run;
  12.                  ");
  13. run;
复制代码

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



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






已有 2 人评分经验 论坛币 学术水平 热心指数 信用等级 收起 理由
Tigflanker + 5 + 3 + 3 + 3 典藏系列
intheangel + 100 + 2 + 2 + 2 精彩帖子

总评分: 经验 + 100  论坛币 + 5  学术水平 + 5  热心指数 + 5  信用等级 + 5   查看全部评分

和谐拯救危机

使用道具

藤椅
pobel 在职认证  发表于 2013-4-28 21:01:21 |只看作者 |坛友微信交流群
论坛的编辑器实在是不敢恭维啊
和谐拯救危机

使用道具

板凳
webgu 发表于 2013-4-28 22:16:04 |只看作者 |坛友微信交流群
pobel 发表于 2013-4-28 21:01
论坛的编辑器实在是不敢恭维啊
嗯,下次我跟论坛的管理员反映下这个问题。
SAS资源
1. SAS 微信:StatsThinking
2. SAS QQ群:348941365

使用道具

报纸
webgu 发表于 2013-4-28 22:17:25 |只看作者 |坛友微信交流群
pobel, 真希望你能写本书,专门解读SAS机制和语句。
SAS资源
1. SAS 微信:StatsThinking
2. SAS QQ群:348941365

使用道具

地板
Bridgenc 发表于 2013-4-29 03:26:53 |只看作者 |坛友微信交流群
thanks, very helpful

使用道具

7
pobel 在职认证  发表于 2013-4-29 06:21:39 |只看作者 |坛友微信交流群
webgu 发表于 2013-4-28 22:17
pobel, 真希望你能写本书,专门解读SAS机制和语句。
现在看书都快看不下去了,写书就更遥远了,浮躁啊
和谐拯救危机

使用道具

8
yongyitian 发表于 2013-4-29 08:30:13 |只看作者 |坛友微信交流群
很好,  支持.

使用道具

9
美髯客 发表于 2013-4-29 08:53:08 |只看作者 |坛友微信交流群
很好,分享一下!

使用道具

10
peterpan_aus 发表于 2013-4-29 08:54:47 |只看作者 |坛友微信交流群
非常强

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-21 00:13