从单个数据集创建多个SAS宏变量列表

时间:2018-10-12 04:53:11

标签: loops sas sas-macro proc-sql

由于宏变量的值的长度不能超过(65534)的最大长度,因此我无法为所有观察结果创建单个宏变量。我想创建一个宏来遍历我的数据集以生成几个数字列表,这些列表可以传递给proc sql中的where语句。

代替此:

*proc sql noprint;
    select ID into :ParaList separated by ','
    from work.ID_LIST(**firstobs=1 obs=5000**);
quit;*

*proc sql noprint;
    select ID into :ParaList2 separated by ','
    from work.ID_LIST(**firstobs=5001 obs=10000**);
quit;*

*proc sql noprint;
    select ID into :ParaList3 separated by ','
    from work.ID_LIST(**firstobs=10001 obs=15000**);
quit;*

*proc sql noprint;
    select ID into :ParaList4 separated by ','
    from work.ID_LIST(**firstobs=15001 obs=20000**);
quit;*

我想要类似的东西:

*proc sql noprint;
    select ID into :List1-Last4 separated by ','
    from work.ID_LIST(**firstobs=1 obs=&LASTOBS** BY 5000);
quit;*

我想创建一个宏来遍历每5000个观察值,直到最后一个观察值为止,以便我可以传递到where语句,例如(&ParaList,&ParaList2,&ParaList3,&ParaList4)中的where id。我知道还有

之类的替代方法
id in (select id from work.table)

,但是在这种情况下,它不起作用。我正在通过SAS查询Hadoop,除传递宏变量列表外没有任何成功。

4 个答案:

答案 0 :(得分:1)

您可以在Hadoop中创建临时表吗?将您的ID_LIST数据上传到临时表,然后在传递查询中使用它。

libname hdp      hadoop noprompt="… connection parameters …";
libname hdp_temp hadoop noprompt="… connection parameters …" dbmstemp=yes;

proc delete data=hdp_temp.id_list;run;
data hdp_temp.id_list;
  set work.my_id_list;
run;

* im not sure on the Hadoop side object naming patterns and default schemas, 
* so this code shows dbo. as is the case in SQL Server;
* SAS libname option dmbstemp=yes for SQL Server causes created tables to be
* referenced as dbo.##<tablename>;

proc sql;
  connect using hadoop;
  create table work.susbset_of_big as
  select * from connection to Hadoop
  ( select * from dbo.my_big_remote_table
    where id in (select id from dbo.##id_list)
  );
quit;

答案 1 :(得分:0)

您可以使用data step do循环和call execute()来完成此操作。

data _null_;
set lib.id_list (nobs=totobs);

do i = 1 to totobs by 5000;

call execute(cat(
    'proc sql;
     select ID into :paralist', i,' separated by ','
     from lib.id_list (firstobs=', i,
    ' obs=5000); quit;'
    ));

call execute(cats('%put |paralist',i,'|;'));

end;
run;

详细了解execute REF1 REF2

中的data step函数调用

上面的调用生成了一行

proc sql;
select id into:paralist1 separated by ','
from lib.id_list (firstobs=1 obs=5000);
quit;

proc sql;
select id into:paralist5001 separated by ','
from lib.id_list (firstobs=5001 obs=5000);
quit;

/* etc */

答案 2 :(得分:0)

您可以轻松地使用数据步骤来生成宏变量。您还应该生成一个宏变量,该宏变量调用所有其他宏变量。

%let n_per_list=5 ;
data _null_;
  length idlist $32000;
  length macrolist $1000 ;
  retain macrolist;
  do i=1 to &n_per_list until (eof);
    set id_list end=eof;
    idlist=catx(',',idlist,id);
  end;
  listno+1;
  call symputx(cats('paralist',listno),idlist);
  macrolist=catx(',',macrolist,cats('&','paralist',listno));
  call symputx('paralist',macrolist);
run;

对于将20个值分为5组的简单测试,将得出以下结果:

151  %put Paralist=%superq(ParaList);
Paralist=&paralist1,&paralist2,&paralist3,&paralist4
152  %put &=Paralist1;
PARALIST1=1,2,3,4,5
153  %put &=Paralist;
PARALIST=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20

或者您可以只看将代码生成到宏中,而不使用宏变量。列表可以生成多长时间应该没有任何限制。您可以尝试找出如何在宏内部打开数据集而不生成任何SAS代码的方法,以便宏调用的结果只是值列表。但是,将宏定义的源代码生成到文件然后%include文件来定义它会容易得多。

filename code temp;
data _null_;
  set id_list end=eof;
  file code lrecl=80;
  if _n_=1 then put '%macro paralist;' ;
  else put ',' @ ;
  put id @ ;
  if eof then put / '%mend paralist;' ;
run;

相同的20个值列表的结果。

163  %include code / source2;
NOTE: %INCLUDE (level 1) file CODE is file /.../#LN00043.
164 +%macro paralist;
165 +1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 ,19 ,20
166 +%mend paralist;
NOTE: %INCLUDE (level 1) ending.
167  %put %paralist;
1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 ,19 ,20

答案 3 :(得分:0)

我喜欢@Richard解决方案,它将使它更加干净高效。如果您的数据集不是很大,您也可以尝试隐式传递。

 Libname SASTAB "yoursaslocation";
 Libname HTAB  your hadoop parameters;

 proc sql;
 create HTAB.newtable as 
 select * froom HTAB.yourtable
 where id in (Select id from SASTAB.yoursastable);