proq sql 宏;遍历列表

proq sql macro; loop through list

我有一个在给定数据集中查找变量名称的宏。如果宏正在寻找的变量名丢失,丢失的变量名将添加到 table:

%macro miss(ds, var);
    %local rc dsid result;
    %let dsid=%sysfunc(open(&ds));
    %if %sysfunc(varnum(&dsid,&var)) > 0 %then %do;
        %put &var present;
    %end;
    %else %do;
        insert into work.compare(missing) values("&var")
    %end;
%mend;

proc datasets library=work nolist nodetails;
    delete compare;
run;

proc sql;
    create table work.compare (missing char(15));
%miss(ctr.panup_in, u_name);
quit;

proc print noobs data=work.compare;
run;

对于 55 个不同的变量名称,此检查需要 运行。目前,我只是将每一个都列为

%miss(ctr.panup_in, varname);

行。

出于实际原因,我想将变量列表指定为列表,例如 %let dictionary=var1 var2 var3 等。我现在的努力是找到一种方法让宏循环遍历变量列表.到目前为止,我尝试过的所有操作都会导致

的 "Stament is not valid" 错误
insert into work.compare(missing) values("&var")

命令。

有人对如何执行此操作有任何建议吗?

这个循环遍历一组变量,其中变量 以“|”分隔。可以使用任何其他分隔符 并在扫描功能中指定。

%macro loop(varlist);
%let i=1;
%do %while (%scan(&varlist, &i, |) ^=%str());
%let var=%scan(&varlist, &i, |); 
%put &var;

*rest of SAS code goes here;

*Increment counter;
%let i=%eval(&i+1);
%end;
%mend;
%let temp=a|b|c|d|e;
%loop(&temp);

你真的需要检查吗。如果缺少要添加的所有变量,您可以定义一个零 obs 数据集,并使用未执行的 SET 来包含它们。

*All variables that you might want to add;
data master0;
   attrib a length=8;
   attrib b length=;
   attrib c length=;
   stop;
   call missing(of _all_);
   run;

*Subset of the variable in master0;
data a;
   do a = 1 to 10;
      output;
      end;
   retain X 1;
   run;

*Create new data with master + a variables;
data a_all;
   set a;
   if 0 then set master0;
   run;
proc print;
   run;

您可以删除不需要的变量,使用修改更新为包含所有变量的母版。

*Create new data with with only wanted variables from master0;
data a_all;
   stop;
   set master0;
   run;
data a_all;
   if 0 then modify a_all;
   set a;
   output;
   run;

另一种选择是将您的变量存储在 table 中 - 很可能它们已经在其中了。也许 dictionary.columns?

事实上,您很可能可以通过 dictionary.columns 简单地完成整个过程。例如:

%let varlist=name age novar;

data values_to_check;
  length name ;
  do _i = 1 to countw("&varlist.");
    name= scan("&varlist.",_i);
    output;
  end;
run;


proc sql;

  create table compare as
    select V.name as missing
    from values_to_check V
    left join
     (Select * from dictionary.columns 
      where memname='CLASS' and libname='SASHELP') D      
      on upcase(V.name)=upcase(D.name)
    where D.name is null
    ;
  quit;

如果您不必创建数据集,那当然会更容易,如果它已经存在——作为另一个确实存在的数据集中的变量列表,或者直接通过数据线或类似的方式创建它。不过,很可能您有一些包含此信息的数据,而不仅仅是硬编码的 %let 语句。

一个示例,它标识了 CLASSFIT 中而不是 CLASS 中的变量(都在 SASHELP 库中):

proc sql;    
  create table compare as
    select V.name as missing
    from  
      (Select * from dictionary.columns 
      where memname='CLASSFIT' and libname='SASHELP')  V
    left join
     (Select * from dictionary.columns 
      where memname='CLASS' and libname='SASHELP') D      
      on upcase(V.name)=upcase(D.name)
    where D.name is null
    ;
  quit;

如果您真的想要 table 的名称不在您的数据集中,那么您可以只使用数据步骤并消除使用宏或 PROC 的复杂性 SQL.

%let ds=sashelp.class;
%let varlist=age sex gender ;
data compare;
  length missing  ;
  dsid=open("&ds");
  do i=1 to countw("&varlist");
    missing = scan("&varlist",i);
    if not varnum(dsid,missing) then output;
  end;
  rc=close(dsid);
  stop;
  keep missing;
run;

现在宏解决方案可能有用的地方是,如果您想传入列表并取出另一个列表,而不生成任何代码。

%macro miss(ds, varlist);
%local dsid i var result;
%let dsid=%sysfunc(open(&ds));
%if (&dsid) %then %do;
  %do i=1 %to %sysfunc(countw(&varlist));
    %let var=%scan(&varlist,&i);
    %if not %sysfunc(varnum(&dsid,&var)) %then %let result=&result &var;
  %end;
  %let rc=%sysfunc(close(&dsid));
%end;
%else %let result=&varlist;
&result.
%mend miss;

这样您就可以在语句中间调用宏,就像函数调用一样。

%put Missing variables are: %miss(sashelp.class,age sex gender);