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

Create several SAS macro variable lists from single dataset

由于宏变量值的长度不能超过 (65534) 的最大长度,我无法为我的所有观察结果创建一个宏变量。我想创建一个宏来遍历我的数据集以生成几个 numeric 列表,我可以将它们传递给 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 语句中,例如 where id in (&ParaList,&ParaList2,&ParaList3,&ParaList4)。我知道有其他选择,例如

id in (select id from work.table)

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

您可以使用 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;

data step REF1 REF2

中阅读有关 execute 函数调用的更多信息

上面的调用生成行

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 */

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

%let n_per_list=5 ;
data _null_;
  length idlist 000;
  length macrolist 00 ;
  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

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

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;

我喜欢@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);