在宏程序中执行调用不会更改数据文件

时间:2018-08-02 16:03:11

标签: macros sas sas-macro

我对该宏编程,该宏使用调用execute将我的旧变量的标签放在新变量上。但是,当我在其他数据集上使用宏时,调用执行不会更改数据集。

%MACRO CHARTONUM2(file=,var=,nbvar=,newvar=,fmt=);
%DO aa=1 %TO &nbvar;
    DATA &file;
        set &file end=eof;
        &newvar&aa=input(put(&var&aa,$3.),3.);
        format &newvar&aa &fmt..;
        if eof then do;
            call execute('data &syslast; set &syslast;');
            call execute('label &newvar&aa = "' || strip(vlabel(&var&aa)) || '";');
            call execute('run;');
        end;
        drop &var&aa;
    RUN;
%END;
%MEND CHARTONUM2;

因此,数据集是动态的,带有参数“文件”。如果我使用2个不同的数据集对该宏运行两次,则调用execute将在第一个数据集中搜索我的变量。其余的运行良好。这是日志:

%CHARCHARTONUM(file=demohealth,var=SEX,deb=1,end=1,newvar=sexn,fmt=
sex);
MPRINT(CHARCHARTONUM):   DATA demohealth;
MPRINT(CHARCHARTONUM):   set demohealth end=eof;
MPRINT(CHARCHARTONUM):   sexn=input(put(SEX, $sex.),3.);
MPRINT(CHARCHARTONUM):   format sexn sex.;
MPRINT(CHARCHARTONUM):   if eof then do;
MPRINT(CHARCHARTONUM):   call execute('data &syslast; set &syslast;');
MPRINT(CHARCHARTONUM):   call execute('label &newvar = "' ||
strip(vlabel(SEX)) || '";');
MPRINT(CHARCHARTONUM):   call execute('run;');
MPRINT(CHARCHARTONUM):   end;
MPRINT(CHARCHARTONUM):   drop SEX_STD;
MPRINT(CHARCHARTONUM):   RUN;

WARNING: The variable SEX_STD in the DROP, KEEP, or RENAME list has never
         been referenced.
MPRINT(CHARCHARTONUM):   data WORK.ASIPRE ;
MPRINT(CHARCHARTONUM):   set WORK.ASIPRE ;
MPRINT(CHARCHARTONUM):   label sexn = "Sex";
MPRINT(CHARCHARTONUM):   run;

我想在任何数据集上启动此宏...有人有想法吗?

3 个答案:

答案 0 :(得分:2)

不要仅仅为了更改标签而重写整个数据集-这是不需要的I / O,如果数据集很大,则可能非常昂贵。一次执行所有转换,同时将动态标签语句生成到宏变量中,以供随后的PROC DATASETS使用,该变量将永久分配新标签。

重复调用numToChar一次执行一个变量也是过多的I / O。

当您要转换多个变量以其格式呈现的表示形式进行复制时,请考虑将以空格分隔的列表作为宏参数传递;变量名称列表,新名称列表和渲染格式列表。但是,在许多情况下,您可能会发现命名约定和具有共同作用的变量可能只需要变量列表和共同格式即可应用。

最后,将变量存储在一个新的变量中是必要的,因为它以格式表示。对该变量及其下游使用情况的回顾可能表明您只需要将格式应用于原始变量即可。

示例代码

data have;
  x=12; y=12.34; z=0.007;
  label 
    x = 'The value of X'
    y = 'Y?, ask Mickey'
    z = 'Zed''s "bike"'
  ;
run;

%macro numToChar(data=, out=&data, vars=, newvars=, formats=);
  %local var newvar fmt labels lib mem;

  data &out;
    set &data;
    %do i = 1 %to %sysfunc(countw(&vars,,S));
      %let var    = %scan(&vars,&i,,S);
      %let newvar = %scan(&newvars,&i,,S);
      %let fmt    = %scan(&formats,&i,,S);

      &newvar = put(&var,&fmt);

      call symput('labels', catx(' ', symget('labels'), "&newvar=" || quote(trim(vlabel(&var)))));
    %end;
  run;

  %let lib = %scan(&syslast,1,.);
  %let mem = %scan(&syslast,2,.);

  proc datasets nolist lib=&lib;
    modify &mem;
    label &labels;
  run;
  quit;
%mend;

options mprint;

%numToChar(
  data=have,
  out=want,
  vars=x y z,
  newvars=x_best y_best z_best,
  formats=best. best. best.
);

答案 1 :(得分:1)

这是一个计时问题。当&syslast生成的代码被压入堆栈时,将评估call execute()的值。您可以使用%nrstr()来延迟评估,直到将代码从要执行的堆栈中拉出为止。

call execute('%nrstr(data &syslast; set &syslast;)');

运行此示例以查看其运行情况。

data one; x=1; run;
data two; x=2;
  call execute('data _null_; set &syslast; put x=; run;');
  call execute('data _null_; set %nrstr(&syslast); put x=; run;');
run;

日志

NOTE: CALL EXECUTE generated line.
1   + data _null_; set WORK.ONE                             ; put x=; run;

x=1
NOTE: There were 1 observations read from the data set WORK.ONE.


2   + data _null_; set &syslast; put x=; run;

x=2
NOTE: There were 1 observations read from the data set WORK.TWO.

但是,因为您已经在运行宏,所以真正的解决方案是修改宏,以便您无需使用调用执行。您还可以在数据的一次传递中创建新变量。并消除不必要的PUT()函数调用。并使格式对新变量的附加更加灵活甚至可选。

%MACRO CHARTONUM2(file=,var=,nbvar=,newvar=,fmt=);
%if %length(&fmt) and not %index(&fmt,.) %then %let fmt=&fmt..;
data _null_;
  set &file ;
%DO aa=1 %TO &nbvar;
  call symputx("label&aa",vlabel(&var&aa),'L');
%END;
  stop;
run;

date &file;
  set &file end=eof;
%DO aa=1 %TO &nbvar;
  &newvar&aa=input(&var&aa,32.);
  format &newvar&aa &fmt;
  label &newvar&aa="&&label&aa" ;
  drop &var&aa;
%END;
run;
%MEND CHARTONUM2;

答案 2 :(得分:0)

&SYSLAST的值何时更新以及何时对该数据步骤进行编译有关。

CALL EXECUTE数据步骤的编译在内部数据步骤完成之前进行。 &SYSLAST的值尚未更新。您可用的版本是因为&FILE的值与&SYSLAST

相同

您可以通过以下示例看到它:

data test;
x=1;
label x="X Label";
run;

data temp;
y=2;
label y="Y Label";
run;

%macro NUMTOCHAR(file=,var=,newvar=,fmt=best.);
data &file;
set &file end=eof;
&newvar=put(&var,&fmt);

if eof then do;
    call execute('data &syslast; set &syslast;');
    call execute('label &newvar = "' || strip(vlabel(&var)) || '";');
    call execute('run;');
end;
run;

%mend;

%numtochar(file=test,var=x,newvar=xc);

您看到第二个数据步骤正在temp而不是test上工作。

将代码更改为:

call execute('data &file; set &file;');