找回密码
 注册
查看: 3424|回复: 0

跟版主crackman读SAS程序(4)

[复制链接]
发表于 2010-8-27 14:31:50 | 显示全部楼层 |阅读模式
本帖最后由 生统家园推荐 于 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.
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|生物统计家园 网站价格

GMT+8, 2024-11-21 18:36 , Processed in 0.030829 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表