本帖最后由 生统家园推荐 于 2010-8-27 14:39 编辑
原程序在这里
在这里提供了两个循环调用宏的方法,一个是用另外一个宏循环调用外部的已经编写好的宏 另外一个是在data步里面调用宏。
%macro outer;
%do i=1 %to 10;
%inner2(0, 1, &i);
%end;
%mend;
%outer
这个是第一个方法,其实这个方法我最熟悉也经常用的一个方法,封装在另外一个宏循环里面,结构清晰,不容易出错。
其实在这里给我们写程序提供了一个思路,对于一个比较复杂的程序来说,我们要学会功能分解,结构化的去设计程序。例如在这个程序里面,
我们讲重复需要实现的过程或者步骤写成一个宏程序,设置好宏参数。解决一个比较复杂问题的时候,将问题分解成若干个小问题,对于每一个问题或者每一个功能写成一个宏模块,但是一定要设计好参数,这个参数是与其他结构模块相互沟通的接口。就想现在建房子一样,都是组合式,每一个部门都是标准化设计,然后组合在一起实现一个整体的需要或者整体的功能。
hopewell的程序里面提供一个宏宇data步交互的方法
%macro inner(x,y,z);
%put NOTE:*** Macro inner: x=&x y=&y z=&z ***;
%mend inner;
data _null_;
do i=1 to 3;
call execute(cats('%inner(0,1,',put(i,best.),')'));
/* %inner(0,1,i);*/
end;
run;
其实要说难理解应该是call execute(cats('%inner(0,1,',put(i,best.),')'));
其实这句话里面cats连接字符函数,最后得出的结果其实就是call execute('%inner(0,1,i)')
但是在这里如果直接写call execute('%inner(0,1,i)')岂不是更简洁?
如果说是没有参数,call execute('%inner') 这样是可以的,但是如果是参数,就注意,如果写成call execute('%inner(0,1,i)'),他会解析成一个宏调用,%inner(0,1,i),同时DATA步停止,而不是我们想的%inner(0,1,1)这样,因此要想得到%inner(0,1,1)这样解析结果,就要对I进行一个处理,把%inner(0,1,1)看做一个字符串,对于这个字符串变化的那个需要用put函数将其转换一个字符,用cats来连接。
至于call execute的使用方法:可以看看下面一个我转载的帖子
[功能]
解析参数,如果解析后的值是sas语句(sas statement),则在下一个步边界(step boundary)执行;
如果此值为macro语言元素(macro language element),则立即执行.
用于在data step中与macro机制进行交互.
[分类]
宏(macro)
[语法]
CALL EXECUTE(argument);
[参数]
argument
指定一个产生宏调用或者sas语句的字符表达式或者常量.argument可以是:
一个字符串,放入引号内
data步的字符变量,不要使用引号括住
一个字符表达式,数据步解析成宏文本表达式(macro text expression)或者sas语句.
[详细]
如果参数被解析成一个宏调用,则宏立刻运行,在这个宏执行时,data步的执行暂停.
如果参数被解释成一个sas语句,或者宏的执行产生sas语句,这些语句在call execute
子程序的所在的data步结束后才执行.
[CALL EXECUTE子程序同步(timing)详解]
当想有条件的执行macro时,CALL EXECUTE很有用.但牢记,如果call execute产生macro language elements,
则他们立即执行;如果call execute产生sas language statements,或者macro language elements产生
sas language statements,这些statements在当前data step执行后执行.
下面两个例子阐述用户使用call execute常有的问题
例1:
data prices;/* ID for price category and actual price */
input code amount;
cards;
56 300
99 10000
24 225
;
%macro items;
%global special;
%let special=football;
%mend items;
data sales;/* incorrect usage */
set prices;
length saleitem $ 20;
call execute('%items');
saleitem=”&special”;
run;
在DATA SALES step中,在data步编译时,对SALEITEM的赋值需要macro变量SPECIAL的值.
但是直到data step执行时,call execute才产生这个值.所以,在log中能看一个
未解析宏变量的消息,并且SALEITEM的值为&special.
在这个例子中,去掉宏定义或者把DATA SALES步放到宏ITEMS中更好.在这两种情况下,
call execute都不必要,也没什么用处.下面是此程序正确的一个版本
data prices;/* ID for price category and actual price */
input code amount;
cards;
56 300
99 10000
24 225
;
%let special=football;/* correct usage */
data sales;
set prices;
length saleitem $ 20;
saleitem=”&special”;
run;
例2:
/* This version of the example shows the problem.*/
data prices;/* ID for price category and actual price */
input code amount;
cards;
56 300
99 10000
24 225
;
data names;/* name of sales department and item sold */
input dept $ item $;
cards;
BB Boat
SK Skates
;
%macro items(codevar=);/* create macro variable if needed */
%global special;
data _null_;
set names;
if &codevar=99 and dept='BB'then call symput('special',item);
run;
%mend items;
data sales;/* attempt to reference macro variable fails */
set prices;
length saleitem $ 20;
500 then
call execute('%items(codevar='|| code || ')');
saleitem=”&special”;
run;
在这个例子中,宏ITEMS生成一个DATA _NULL_ step,这个step在DATA SALES step执行之后
才执行.而在DATA SALES编译时就需要DATA _NULL_ step中创建的SPECIAL.
正确的一个例子:
/* This version solves the problem.*/
data prices;/* ID for price category and actual price */
input code amount;
cards;
56 300
99 10000
24 225
;
data names;/* name of sales department and item sold */
input dept $ item $;
cards;
BB Boat
SK Ski
;
%macro items(codevar=);/* create macro variable if needed */
%global special;
data _null_;
set names;
if &codevar=99 and dept='BB'then
call symput('special',item);
run;
%mend items;
data _null_;/* call the macro in this step */
set prices;
500 then
call execute('%items(codevar='|| code || ')');
run;
data sales;/* use the value created by the macro in this step */
set prices;
length saleitem $ 20;
saleitem=”&special”;
run;
上面的例子使用一个DATA _NULL_ step来调用宏ITEMS.在这个step结束后,由ITEMS产生的
DATA _NULL_ step执行,并创建宏变量SPECIAL.
|