#sas #sas-macro
#sas #sas-макрос
Вопрос:
У меня есть таблица, содержащая имена нескольких других таблиц в проекте.
Как показано в таблице СПИСКА ниже:
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 amp;num;
PROC SQL NOPRINT;
SELECT TABLE_NAME INTO : VAR_TABLE_NAME
FROM WORK.LIST
WHERE TABLE_ID = amp;i.;
QUIT;
PROC SQL;
CREATE TABLE TABLE_amp;i AS
SELECT *
FROM WORK.amp;VAR_TABLE_NAME;
QUIT;
%END;
%MEND;
%MAKE_TABLE;
Это работает, но я думаю, что это не самый эффективный метод.
Комментарии:
1. Я добавил решение, которое использовал для своего вопроса. Но я думаю, что это не самый эффективный.
Ответ №1:
Обычным шаблоном для этого является создание макроса, который принимает имя таблицы в качестве параметра.
%MACRO MAKE_TABLE(TABLE_NAME);
...
FROM WORK.amp;TABLE_NAME
...
%MEND MAKE_TABLE;
Затем вы можете использовать CALL EXECUTE для генерации одного вызова макроса для каждого наблюдения в вашей таблице СПИСКА.
data _null_;
set list;
call execute(cats('%nrstr(%make_table)(',table_name,')'));
run;
Добавление %nrstr()
вокруг %make_table
гарантирует, что сам вызов макроса будет помещен в стек для запуска после шага данных вместо кода, который он генерирует. Это облегчит чтение журнала. Это также предотвратит проблемы с синхронизацией, когда у макроса есть логика, которая зависит от оценки результатов выполнения кода, который генерирует макрос.
Ответ №2:
Выберите имена таблиц 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 amp;SQLOBS;
%let table_name = %scan(amp;names,amp;i);
proc sql;
...query here...
... from amp;table_name ...
...query here...
quit;
%end;
%mend;
%do_same_query_each_table
Комментарии:
1. Этот метод более эффективен, поскольку он выполняет одну процедуру SQL на каждой итерации. Метод, который я сделал, выполняет два процесса SQL на каждой итерации.
Ответ №3:
Итак, я написал макрос, который выполняет запросы, изменяя имена таблиц.
PROC SQL NOPRINT; SELECT COUNT(*) INTO : NUM FROM WORK.INICIO; QUIT;
%MACRO MAKE_TABLE;
%DO i = 1 %TO amp;num;
PROC SQL NOPRINT;
SELECT TABLE_NAME INTO : VAR_TABLE_NAME
FROM WORK.LIST
WHERE TABLE_ID = amp;i.;
QUIT;
PROC SQL;
CREATE TABLE TABLE_amp;i AS
SELECT *
FROM WORK.amp;VAR_TABLE_NAME;
QUIT;
%END;
%MEND;
%MAKE_TABLE;
Это работает, но я считаю, что это не самый эффективный метод.
Однако этот метод зависит от идентификатора в таблице СПИСКА.
Комментарии:
1. Итак, вы хотите изменить разумные имена таблиц на какое-то относительно анонимное имя? Что вы хотите от TABLE_ID ?
2. Нет. На самом деле, идея состоит в том, чтобы запускать SQL-запрос для каждой таблицы в TABLE_NAME, используя PROC SQL. В этом примере я сделал «SELECT * FROM», но это был всего лишь пример (я мог бы использовать GROUP BY , WHERE и т. Д.). Суть идеи состоит в том, чтобы иметь таблицу, содержащую имена нескольких других таблиц, и выполнять итерации по этой таблице, генерируя запросы с помощью PROC SQL. Важно то, как сообщить имя таблицы в «FROM WORK.amp;VAR_TABLE_NAME».