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。