迭代查询的行创建新表
Iterating rows of a query creating new tables
我有一个 table 包含项目中其他几个 table 的名称。
如下列表table:
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
;
我需要在这个项目的所有 table 中通过查询执行某种处理。
所以我写了一个宏,通过更改 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;
有效,但我认为不是最有效的方法。
所以我写了一个宏,通过更改 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;
有效,但我认为这不是最有效的方法。
但是,此方法依赖于 LIST 中的一个 ID table。
Select table 命名 into
一个可以为每个名称解析的宏变量,它又用于进一步的代码生成。
示例:
%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
一个正常的模式是制作一个将 table 名称作为参数的宏。
%MACRO MAKE_TABLE(TABLE_NAME);
...
FROM WORK.&TABLE_NAME
...
%MEND MAKE_TABLE;
然后您可以使用 CALL EXECUTE 为您的 LIST 中的每个观察生成一个宏调用 table。
data _null_;
set list;
call execute(cats('%nrstr(%make_table)(',table_name,')'));
run;
在 %make_table
周围添加 %nrstr()
将确保在数据步骤之后将宏调用本身推入堆栈 运行 而不是它生成的代码。这将使日志更易于阅读。当宏具有依赖于评估执行宏生成的代码的结果的逻辑时,它还将防止计时问题。
我有一个 table 包含项目中其他几个 table 的名称。
如下列表table:
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
;
我需要在这个项目的所有 table 中通过查询执行某种处理。
所以我写了一个宏,通过更改 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;
有效,但我认为不是最有效的方法。
所以我写了一个宏,通过更改 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;
有效,但我认为这不是最有效的方法。
但是,此方法依赖于 LIST 中的一个 ID table。
Select table 命名 into
一个可以为每个名称解析的宏变量,它又用于进一步的代码生成。
示例:
%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
一个正常的模式是制作一个将 table 名称作为参数的宏。
%MACRO MAKE_TABLE(TABLE_NAME);
...
FROM WORK.&TABLE_NAME
...
%MEND MAKE_TABLE;
然后您可以使用 CALL EXECUTE 为您的 LIST 中的每个观察生成一个宏调用 table。
data _null_;
set list;
call execute(cats('%nrstr(%make_table)(',table_name,')'));
run;
在 %make_table
周围添加 %nrstr()
将确保在数据步骤之后将宏调用本身推入堆栈 运行 而不是它生成的代码。这将使日志更易于阅读。当宏具有依赖于评估执行宏生成的代码的结果的逻辑时,它还将防止计时问题。