循环遍历表并在 SAS 中加入它们
Looping through tables and joining them in SAS
我想不出解决一个问题。
我在一个 SAS 库中有未知数量的表。我想做一个循环,遍历它们和 "UNION ALL" 那些表。
表是预先检查过的,它们具有相同的结构。此表包含历史化数据,因此它应该是 Union all。
我尝试了以下脚本,但它会搜索所有可能性但不会执行 UNION ALL。
我很感激任何解决这个问题的想法。
%macro union_tables(table_name, last_extract);
%do i=1 %to &last_extract.;
select * from data.&table_name&i
union all
%end;
select * from data.&table_name&i
%mend;
proc sql;
create table Full_history as
%union_tables(Table_,1216);
quit;
提前谢谢你。
您的宏正在查找名为 table_1
到 table_1216
的表,如果找不到不存在的表,则会向您报错。您需要更改循环,使其仅尝试获取实际存在的表的并集。
如果:
A)所有文件名的总长度+它们的libname前缀+句点<32767;和
B)你的组成文件都在一个库中;和
C) 你的文件都以 'Table_'
开头
data _null_;
length datasets 767; *make sure this is long enough to hold all your dataset names + their libname prefix. 32767 is the max string length;
retain datasets;
set sashelp.vstable end=eof; *This system view holds all known datasets in all known libraries;
where upcase(libname)='DATA'; *The libname where you dsets live. Use all uppercase;
if index(UPCASE(memname),'TABLE_') =1 /*Your code shows all datasets begin with 'Table_'*/ then
datasets=trim(datasets)||
' '||trim(libname)||
'.'||trim(memname);
if eof then call symput('datasets',datasets);
run;
%put &datasets; *print them to the log;
data all_the_datasets;
set &datasets;
run;
作为参考,我从 Richardson 和 Rossland 的 SUGI 29 论文的第 5 页抄录了大部分内容。
也许您可以放弃宏并使用 SET 语句。
data Many;
set table_: open=defer;
run;
如果表在变量方面完全相同并且类型 Open=defer 可以节省大量内存。
无论您的数据集如何命名,只需在创建顺序变量后将它们全部放入列表中并将它们放在一起(将 work.
替换为您的库命名的任何内容):
/* put all dataset names into a dataset */
proc contents data = work._all_ noprint out=ds_names(keep=memname); run;
/* dedupe the dataset and create an order variable */
data ds_names1; set ds_names;
by memname;
if first.memname;
order_var + 1;
run;
/* put the ordered datasets into a macro variable list */
proc sql noprint;
select distinct(memname)
into: ds_list separated by " "
from ds_names1
order by order_var;
quit;
%put &ds_list.;
/* append all the datasets together in order */
%macro append_instead_of_set(ds_list);
%do i=1 %to %sysfunc(countw(&ds_list.));
%let ds = %scan(&ds_list.,&i.);
proc append data = &ds. base=full force; run;
%end;
%mend;
%append_instead_of_set(&ds_list.);
感谢大家的回复。我用了很少的东西来达到我需要的结果。
我想 post 我自己的结果,因为我使用了来自 Amw 5G 和 Foxer 用户的部分代码。
/* get list of the tables */
%MACRO SHOW_TABLES(libname, regex);
proc sql noprint;
select memname
into :list_tables separated by " "
from dictionary.tables
where libname="&libname." and upcase(memname) like upcase("%quote(%%)&®ex%")
order by memname;
quit;
%MEND;
%show_tables(DATA, Table_);
%put LIST OF TABLES: &list_tables.;
/* putting data sets together*/
DATA data.Full_history;
SET data.&list_tables.;
RUN;
这样它就把我所有的 table 放在一起,即使有一个不同的结构。因为 tables 可以随时间变化(可以删除某些列或添加新的列)。
对于proc append
table应该有相同的结构。因此,就我而言,使用 data set
.
是合理的
我想不出解决一个问题。
我在一个 SAS 库中有未知数量的表。我想做一个循环,遍历它们和 "UNION ALL" 那些表。
表是预先检查过的,它们具有相同的结构。此表包含历史化数据,因此它应该是 Union all。 我尝试了以下脚本,但它会搜索所有可能性但不会执行 UNION ALL。
我很感激任何解决这个问题的想法。
%macro union_tables(table_name, last_extract);
%do i=1 %to &last_extract.;
select * from data.&table_name&i
union all
%end;
select * from data.&table_name&i
%mend;
proc sql;
create table Full_history as
%union_tables(Table_,1216);
quit;
提前谢谢你。
您的宏正在查找名为 table_1
到 table_1216
的表,如果找不到不存在的表,则会向您报错。您需要更改循环,使其仅尝试获取实际存在的表的并集。
如果: A)所有文件名的总长度+它们的libname前缀+句点<32767;和 B)你的组成文件都在一个库中;和 C) 你的文件都以 'Table_'
开头data _null_;
length datasets 767; *make sure this is long enough to hold all your dataset names + their libname prefix. 32767 is the max string length;
retain datasets;
set sashelp.vstable end=eof; *This system view holds all known datasets in all known libraries;
where upcase(libname)='DATA'; *The libname where you dsets live. Use all uppercase;
if index(UPCASE(memname),'TABLE_') =1 /*Your code shows all datasets begin with 'Table_'*/ then
datasets=trim(datasets)||
' '||trim(libname)||
'.'||trim(memname);
if eof then call symput('datasets',datasets);
run;
%put &datasets; *print them to the log;
data all_the_datasets;
set &datasets;
run;
作为参考,我从 Richardson 和 Rossland 的 SUGI 29 论文的第 5 页抄录了大部分内容。
也许您可以放弃宏并使用 SET 语句。
data Many;
set table_: open=defer;
run;
如果表在变量方面完全相同并且类型 Open=defer 可以节省大量内存。
无论您的数据集如何命名,只需在创建顺序变量后将它们全部放入列表中并将它们放在一起(将 work.
替换为您的库命名的任何内容):
/* put all dataset names into a dataset */
proc contents data = work._all_ noprint out=ds_names(keep=memname); run;
/* dedupe the dataset and create an order variable */
data ds_names1; set ds_names;
by memname;
if first.memname;
order_var + 1;
run;
/* put the ordered datasets into a macro variable list */
proc sql noprint;
select distinct(memname)
into: ds_list separated by " "
from ds_names1
order by order_var;
quit;
%put &ds_list.;
/* append all the datasets together in order */
%macro append_instead_of_set(ds_list);
%do i=1 %to %sysfunc(countw(&ds_list.));
%let ds = %scan(&ds_list.,&i.);
proc append data = &ds. base=full force; run;
%end;
%mend;
%append_instead_of_set(&ds_list.);
感谢大家的回复。我用了很少的东西来达到我需要的结果。
我想 post 我自己的结果,因为我使用了来自 Amw 5G 和 Foxer 用户的部分代码。
/* get list of the tables */
%MACRO SHOW_TABLES(libname, regex);
proc sql noprint;
select memname
into :list_tables separated by " "
from dictionary.tables
where libname="&libname." and upcase(memname) like upcase("%quote(%%)&®ex%")
order by memname;
quit;
%MEND;
%show_tables(DATA, Table_);
%put LIST OF TABLES: &list_tables.;
/* putting data sets together*/
DATA data.Full_history;
SET data.&list_tables.;
RUN;
这样它就把我所有的 table 放在一起,即使有一个不同的结构。因为 tables 可以随时间变化(可以删除某些列或添加新的列)。
对于proc append
table应该有相同的结构。因此,就我而言,使用 data set
.