从单个数据集创建多个 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;
中阅读有关 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=¶list1,¶list2,¶list3,¶list4
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);
由于宏变量值的长度不能超过 (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;
中阅读有关 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=¶list1,¶list2,¶list3,¶list4
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);