Sas 迭代查询的行以创建新表
我有一个表,其中包含项目中其他几个表的名称 如下表所示:Sas 迭代查询的行以创建新表,sas,sas-macro,Sas,Sas Macro,我有一个表,其中包含项目中其他几个表的名称 如下表所示: DATA WORK.LIST; INPUT TABLE_ID TABLE_NAME : $CHAR25.; DATALINES; 1 CUSTOMERS 2 PRODUCTS 3 ORDERS ; DATA WORK.CUSTOMERS; INPUT CUSTOMER_ID CUSTOMER_NAME $; DATALINES; 1 David 2 Jose 3 Marcos 4 Josue ; DATA WORK.PRODUCTS;
DATA WORK.LIST; INPUT TABLE_ID TABLE_NAME : $CHAR25.;
DATALINES;
1 CUSTOMERS
2 PRODUCTS
3 ORDERS
;
DATA WORK.CUSTOMERS; INPUT CUSTOMER_ID CUSTOMER_NAME $;
DATALINES;
1 David
2 Jose
3 Marcos
4 Josue
;
DATA WORK.PRODUCTS; INPUT PRODUCT_ID PRODUCT_NAME $;
DATALINES;
41574 Tevision
35741 Refrigerator
74585 Cooker
;
DATA WORK.ORDERS; INPUT ORDER_ID CUSTOMER_ID PRODUCT_ID;
DATALINES;
741 1 41574
987 4 74585
888 4 35741
111 2 41574
;
我需要通过查询在这个项目的所有表中执行某种处理
因此,我编写了一个宏,通过更改表的名称来执行查询
PROC SQL NOPRINT; SELECT COUNT(*) INTO : NUM FROM WORK.INICIO; QUIT;
%MACRO MAKE_TABLE;
%DO i = 1 %TO #
PROC SQL NOPRINT;
SELECT TABLE_NAME INTO : VAR_TABLE_NAME
FROM WORK.LIST
WHERE TABLE_ID = &i.;
QUIT;
PROC SQL;
CREATE TABLE TABLE_&i AS
SELECT *
FROM WORK.&VAR_TABLE_NAME;
QUIT;
%END;
%MEND;
%MAKE_TABLE;
PROC SQL NOPRINT; SELECT COUNT(*) INTO : NUM FROM WORK.INICIO; QUIT;
%MACRO MAKE_TABLE;
%DO i = 1 %TO #
PROC SQL NOPRINT;
SELECT TABLE_NAME INTO : VAR_TABLE_NAME
FROM WORK.LIST
WHERE TABLE_ID = &i.;
QUIT;
PROC SQL;
CREATE TABLE TABLE_&i AS
SELECT *
FROM WORK.&VAR_TABLE_NAME;
QUIT;
%END;
%MEND;
%MAKE_TABLE;
它可以工作,但我认为这不是最有效的方法。因此我编写了一个宏,通过更改表名来执行查询
PROC SQL NOPRINT; SELECT COUNT(*) INTO : NUM FROM WORK.INICIO; QUIT;
%MACRO MAKE_TABLE;
%DO i = 1 %TO #
PROC SQL NOPRINT;
SELECT TABLE_NAME INTO : VAR_TABLE_NAME
FROM WORK.LIST
WHERE TABLE_ID = &i.;
QUIT;
PROC SQL;
CREATE TABLE TABLE_&i AS
SELECT *
FROM WORK.&VAR_TABLE_NAME;
QUIT;
%END;
%MEND;
%MAKE_TABLE;
PROC SQL NOPRINT; SELECT COUNT(*) INTO : NUM FROM WORK.INICIO; QUIT;
%MACRO MAKE_TABLE;
%DO i = 1 %TO #
PROC SQL NOPRINT;
SELECT TABLE_NAME INTO : VAR_TABLE_NAME
FROM WORK.LIST
WHERE TABLE_ID = &i.;
QUIT;
PROC SQL;
CREATE TABLE TABLE_&i AS
SELECT *
FROM WORK.&VAR_TABLE_NAME;
QUIT;
%END;
%MEND;
%MAKE_TABLE;
这是有效的,但我相信这不是最有效的方法
但是,此方法取决于列表表中的ID。因此我编写了一个宏,通过更改表名来执行查询
PROC SQL NOPRINT; SELECT COUNT(*) INTO : NUM FROM WORK.INICIO; QUIT;
%MACRO MAKE_TABLE;
%DO i = 1 %TO #
PROC SQL NOPRINT;
SELECT TABLE_NAME INTO : VAR_TABLE_NAME
FROM WORK.LIST
WHERE TABLE_ID = &i.;
QUIT;
PROC SQL;
CREATE TABLE TABLE_&i AS
SELECT *
FROM WORK.&VAR_TABLE_NAME;
QUIT;
%END;
%MEND;
%MAKE_TABLE;
PROC SQL NOPRINT; SELECT COUNT(*) INTO : NUM FROM WORK.INICIO; QUIT;
%MACRO MAKE_TABLE;
%DO i = 1 %TO #
PROC SQL NOPRINT;
SELECT TABLE_NAME INTO : VAR_TABLE_NAME
FROM WORK.LIST
WHERE TABLE_ID = &i.;
QUIT;
PROC SQL;
CREATE TABLE TABLE_&i AS
SELECT *
FROM WORK.&VAR_TABLE_NAME;
QUIT;
%END;
%MEND;
%MAKE_TABLE;
data _null_;
set list;
call execute(cats('%nrstr(%make_table)(',table_name,')'));
run;
这是有效的,但我相信这不是最有效的方法
但是,此方法取决于列表表中的ID。将表名选择到一个宏变量中,该宏变量可以对每个名称进行解析,然后在进一步的代码生成中使用该宏变量
data _null_;
set list;
call execute(cats('%nrstr(%make_table)(',table_name,')'));
run;
例如:
%macro do_same_query_each_table;
proc sql noprint;
select table_name into :names separated by ' ' from work.list;
quit;
%local i table_name;
%do i = 1 %to &SQLOBS;
%let table_name = %scan(&names,&i);
proc sql;
...query here...
... from &table_name ...
...query here...
quit;
%end;
%mend;
%do_same_query_each_table
将表名选择到一个宏变量中,该宏变量可以对每个名称进行解析,然后在进一步的代码生成中使用
例如:
%macro do_same_query_each_table;
proc sql noprint;
select table_name into :names separated by ' ' from work.list;
quit;
%local i table_name;
%do i = 1 %to &SQLOBS;
%let table_name = %scan(&names,&i);
proc sql;
...query here...
... from &table_name ...
...query here...
quit;
%end;
%mend;
%do_same_query_each_table
通常的模式是生成一个以表名为参数的宏
%MACRO MAKE_TABLE(TABLE_NAME);
...
FROM WORK.&TABLE_NAME
...
%MEND MAKE_TABLE;
然后,您可以使用CALL EXECUTE为列表中的每个观察生成一个宏调用
data _null_;
set list;
call execute(cats('%nrstr(%make_table)(',table_name,')'));
run;
在%make_表周围添加%nrstr将确保宏调用本身被推送到堆栈上,以便在数据步骤之后运行,而不是在它生成的代码之后运行。这将使日志更易于阅读。当宏具有依赖于对宏生成的代码执行结果进行评估的逻辑时,它还可以防止计时问题。通常的做法是生成一个以表名为参数的宏
%MACRO MAKE_TABLE(TABLE_NAME);
...
FROM WORK.&TABLE_NAME
...
%MEND MAKE_TABLE;
然后,您可以使用CALL EXECUTE为列表中的每个观察生成一个宏调用
data _null_;
set list;
call execute(cats('%nrstr(%make_table)(',table_name,')'));
run;
在%make_表周围添加%nrstr将确保宏调用本身被推送到堆栈上,以便在数据步骤之后运行,而不是在它生成的代码之后运行。这将使日志更易于阅读。当宏的逻辑依赖于对宏生成的代码执行结果的评估时,它还可以防止计时问题。那么您想将表的合理名称更改为相对匿名的名称吗?您想对表\ ID做什么?不想。实际上,我们的想法是使用PROC SQL为表\名称中的每个表运行SQL查询。在那个例子中,我做了一个SELECT*FROM,但这只是一个我可以使用groupby、WHERE等的例子。。该思想的核心是拥有一个包含其他几个表的名称的表,并通过procsql迭代该表生成查询。重要的是如何在FROM WORK中通知表名。&VAR_table_name。那么您想将合理的表名更改为相对匿名的名称吗?您想对表\ ID做什么?不想。实际上,我们的想法是使用PROC SQL为表\名称中的每个表运行SQL查询。在那个例子中,我做了一个SELECT*FROM,但这只是一个我可以使用groupby、WHERE等的例子。。该思想的核心是拥有一个包含其他几个表的名称的表,并通过procsql迭代该表生成查询。重要的是如何在FROM WORK中通知表名。&VAR_table_name。我在问题中添加了我使用的解决方案。但我认为这不是最有效的。我在问题中添加了我使用的解决方案。但是我认为它不是最有效的,这种方法更有效,因为它在每次迭代中执行一个PROC-SQL。我使用的方法在每次迭代中执行两个PROC-SQL。这种方法效率更高,因为它在每次迭代中执行一个PROC-SQL。我使用的方法在每次迭代中执行两个PROC-SQL。