【问题标题】:Looping over libraries in SAS在SAS中循环库
【发布时间】:2014-03-05 15:07:38
【问题描述】:

我有数千个文件名 CLICK,它们都位于我的 linux 上的不同文件夹中。我已将每个文件夹分配给一个库,并且我正在尝试提取每个单击文件(并最终附加,而不是在下面显示的代码中)。这就是我所做的

   `%let listlib=
A B C;

%macro char_loop();
%let i=1;
%let v=%scan(&listlib,&i);
%do %while(&v ne ) ;

data click&v;
     set &v.click;
     type = &v;
run;

%let i=%eval(&i+1);
%let v=%scan(&listlib,&i);
%end;
%mend;
%char_loop;` 

但是,SAS 似乎无法循环通过“set &v.click;”,因此正在更改 lib.日志显示“WORK.ACLICK.DATA 不存在”。我在这里错过了什么?

【问题讨论】:

    标签: loops macros sas


    【解决方案1】:

    &v. 是宏变量 - & 开始,. 终止。 . 不是必需的,如果空格或分号之类的东西使终止发生的位置很明显,但它在技术上是一个组件。所以你需要

    set &v..click
    

    获取实际期间。

    另一方面,SAS 在这类事情上并不是很擅长。你最好得到 perl 或类似的东西来将点击文件收集到一个目录中,或者更好地将它们组合到一个文件中(我之前实际上已经用点击流文件做过这个)。 SAS 在打开和关闭大量单个文件方面效率不高,而且需要更长的时间。

    在此处添加另一个答案,如果您要一次性设置它们(这是一个好主意),最好的方法可能不是宏循环。您可以更轻松地这样做:

    *macro to define an element of the set statement;
    %macro set(lib=);
    &lib..click
    %mend set;
    
    *proc sql to generate a list of these calls from dictionary.tables - make sure you do not have any tables you need excluded from this, and if so use WHERE to do so;
    proc sql;
    select cats('%set(lib=',libname,')')
    into :setlist separated by ' '
    from dictionary.tables
    where memname='CLICK';
    quit;
    
    *set them;
    data want;
    set &setlist. indsname=indsn;
    type = scan(indsn,1,'.');
    run;
    

    通常,宏循环比通过常规的旧数据步骤和 SQL 执行更复杂、更慢。 indsname 适用于 9.3+。

    【讨论】:

    • 感谢indsname 选项!还没有在文档中注意到它!这比从in 变量构建type 的笨重数组要好得多。
    • @alexander 如果您不熟悉,您可能需要阅读字典表和 sashelp 视图;他们可以很有帮助。 Dictionary.table 包含库和数据集名称 (memname),以及指定库中每个数据集的 许多 其他属性。如果您预先分配了数千个库,则从其中提取数据有时需要一段时间,尤其是在您使用其中一个视图时。这是 9.4 文档:support.sas.com/documentation/cdl/en/sqlproc/65065/HTML/default/…
    • 太棒了!并感谢您的额外阅读。这很有帮助。
    【解决方案2】:

    正如乔指出的那样,主要问题是缺少第二个句号 (&v..)

    也就是说,如果您在初始读取时设置它们而不是制作大量工作文件以随后将它们连接在一起,那么对您来说应该更快一些。

    这样的事情应该可以工作:

    *******************************************************************; 
    *** a few test datasets.
    ***   note:  I prefixed that dataset with the libname because 
    ***          they are all technically in the same directory
    ***          and to highlight the difference between &v. and &v..
    *******************************************************************; 
    libname a (work); 
    libname b (work); 
    libname c (work); 
    
    data a.aclick; 
     do i = 1 to 10; 
      output;
     end; 
    run; 
    
    data b.bclick; 
     do j = 1 to 10; 
      output;
     end; 
    run; 
    
    data c.cclick; 
     do k = 1 to 10; 
      output;
     end; 
    run; 
    
    
    *** modified macro  ****;    
    
    %macro char_loop(listlib=);
    %let ListN=%eval(%length(&listlib)-%length(%sysfunc(compress(&listlib)))+1); 
    data click(drop=_i);
    set
        %do i=1 %to &listN ;
         %let v=%scan(&listlib,&i);
           &v..&v.click (in=&v)
         %end; 
      ; 
    
    array _t &listlib; 
    do _i= 1 to &listN; 
      if _t(_i)=1 then type=vname(_t(_i)); 
    end; 
    run;
    
    %mend;
    %char_loop(listlib=a b c );
    proc print data=click; 
    run; 
    

    【讨论】:

    • 好主意。不过,我认为您不需要使用宏循环;添加到我的答案中以显示更有效的方法。
    • 太好了。完美运行!谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多