SAS宏修改

时间:2017-11-23 14:37:35

标签: sas

我有两个代表日期的值:

 a=101 and b=103

下面是第一个保存在单独文件one.sas中的宏:

 %global time nmall;
 %let nmall =;
 %macro pmall;
 %do i=&a. %to &b;
 %if &i =&a. then %do;
 %let nmall=&nmall.&i;
 %end;
 %else %let nmall=&nmall.,&i;
 end;
 %put (&nmall);
 %mend;

 %pmall;

因此,pmall以上给出了值101,102,103

下面是第二个宏:

%include “one.as”;

%macro c(a=,b=);
%let m=;
%let m1=;
%do i =&a %to &b;
%let o=&i;

proc sql;
 create table new&o as select * from data where nb in(&o.);quit;

%let m =&m.date&o;

data date&o.;
set date&o.;
if pass =&o.;
run;

proc sort data=date&o.;
by flag;
end;

data output &a._&b.;
set &m;
%mend;

上面的宏会创建三个数据集date101 date102date 103,然后将其附加到output101_103

我正在尝试修改上面的宏,以便我不会使用%macro%mend方法。以下是修改后的宏代码:

data a_to_c;
do o=&a to &c;
output;
end;
run;

所以上面的代码在数据集101 102 103的变量o中的值为a_to_c

 data _null_;
 set a_to_c;
 call execute ('create table new’||strip(o)||' as select * from data 
 where nb in(’||strip(o)||' );quit;’);
 run;

我想知道如何做以下事情。

  1. 在数据步骤pmall内的修改后的宏中的宏变量中创建data a_to_c值,以便我可以进一步使用它。
  2. 如何从第一个宏代码中的%let m宏转到我上面开发的新代码。

2 个答案:

答案 0 :(得分:1)

  

Pmall是宏变量,它将包含由值分隔的值列表   逗号。在我的修改宏中,我想创建pmall作为宏变量   在datastep数据a_to_c;做o =& a到& c;输出;结束;跑; - geetha   anand 1分钟前

使用CALL SYMPUTX()函数在数据步骤中创建宏变量。

data a_to_c;
  length pmall $200 ;
  do o=&a to &c; 
    pmall=catx(',',pmall,o);
    output; 
  end; 
  call symputx('pmall',pmall);
  drop pmall;
run;

如果您真的想要在没有SAS宏的情况下生成代码,可以使用CALL EXECUTE()或将代码写入文件并使用%INCLUDE来运行它。或者对于小块代码,您可以尝试将代码放在宏变量中,但宏变量只能包含64K字节。

很难说你发布了什么代码要生成的代码。假设您要为序列中的每个值生成一个新数据集,然后将其附加到某个聚合数据集。因此,对于第一次循环,您的代码可能就像这两个步骤一样简单。首先以正确的顺序创建适当的子集,然后将结果附加到聚合数据集。

proc sort data=nb out=date101 ;
  where nb=101 ;
  by flag ;
run;

proc append base=date101_103 data=date101 force;
run;

然后通过循环接下来两次看起来相同,只有“101”将被序列中的当前值替换。

因此,使用CALL EXECUTE您的程序可能如下所示:

%let a=101;
%let c=103;
proc delete data=date&a._&c ;
run;
data _null_;
  do nb=&a to &c; 
    call execute(catx(' ','proc sort data=nb out=',cats('date',nb,'),';'));
    call execute(cats('where nb=',nb,';')) ;
    call execute('by flag; run;');
    call execute("proc append base=date&a._&c data=");
    call execute(cats('date',nb));
    call execute(' force; run;');
  end;
run;

将其写入要通过%INCLUDE运行的文件将如下所示:

filename code temp ;
data _null_;
  file code ;
  do nb=&a to &c; 
    put 'proc sort data=nb out=date' nb ';'
      / '  where ' nb= ';'
      / '  by flag;'
      / ';'
      / "proc append base=date&a._&c data=date" nb 'force;'
      / 'run;'
    ;
  end;
run;
proc delete data=date&a._&c ;
run;
%include code / source2;

如果目标只是创建聚合数据集而您不需要保留较小的中间数据集,那么您可以在每次循环中使用相同的名称作为中间数据集。这将使代码生成更容易,因为只有那个地方需要根据当前值进行更改。同样,即使对于10或20个值的序列,您也只需要有两个数据集名称。它将占用更少的空间并减少工作库中的混乱。

答案 1 :(得分:1)

格塔:

我认为如果你从一个以数据为中心的显式解决方案出发并将显着特征抽象为宏符号(又称变量),你会发现这个过程的宏观化要容易得多

最终解决方案似乎是:

data output_101_to_103;
  set original_data;
  where nb between 101 and 103;
run;
proc sort data=output_101_to_103;
  by nb flag;
run;

在这种情况下,您可以编写一个宏,将101抽象为FIRST,将103抽象为最后。数据集也可以抽象化。抽象的部分被指定为宏参数。

%macro subsetter(DATA=, FIRST=, LAST, OUTPREFIX=OUTPUT);
  %local out;
  %let out = &OUTPREFIX._&FIRST._&LAST.;

  data &out;
    set &DATA.;
    where nb between &FIRST. and &LAST.;
    * condition = "between &FIRST. and &LAST."; * uncomment if you want to carry along the condition into your output data set;
  run;
  proc sort data=&out;
    by nb flag;
  run;
%mend;

并用作

%subsetter (data=original_data, first=101, last=103, outprefix=output)

注意:如果您确实在输出数据中保留了condition变量,那么您将无法在将来的数据步骤中将其直接用作源代码语句,如 {{1} }

我想你也可以将NB和FLAG作为参数传递 - 但是你接近宏的效用收益递减点。

宏观化我所展示的具体例子并没有多大意义,除非你需要在一个记录良好的框架中执行很多不同的FIRST和LAST变体。有时候,最好不要抽象代码并使用特定的案例。为什么?因为当抽象的部分太多时,宏调用几乎与您生成的特定代码一样长,抽象只会妨碍理解。

如果宏只是简单地砍掉数据并重新组合数据,那么最好使用where,by和class语句重新思考流程并对其进行抽象。