SAS:如何在 proc sql WHERE 语句中迭代数据集元素?

SAS : How to iterate a dataset elements within the proc sql WHERE statement?

我需要使用 proc sql

创建多个 table
   proc sql;

   /* first city */
   create table London as 
   select * from connection to myDatabase 
   (select * from mainTable 
    where city = 'London'); 

   /* second city */
   create table Beijing as 
   select * from connection to myDatabase 
   (select * from mainTable 
    where city = 'Beijing');

   /* . .  the same thing for other cities */

   quit; 

这些城市的名称在 sas table myCities

如何将 data 步骤嵌入 proc sql 以遍历所有城市?

  1. 您需要将 proc sql 代码放入 SAS 宏中。
  2. 为 City 创建一个宏变量(在我的示例中,我将宏变量命名为 "City")。
  3. 从数据步程序执行宏。由于 Datastep 程序针对每个观察处理一个,因此无需创建复杂的逻辑来迭代。

    data mycities;
        infile datalines dsd;
        input macrocity $ 32.;
        datalines;
    London
    Beijing
    Buenos_Aires
    ;
    run;
    
    %macro createtablecity(city=);
    proc sql;
       /* all cities  */
       create table &city. as 
       select * from connection to myDatabase 
       (select * from mainTable 
        where city = "&city.");
    quit; 
    %mend;
    
    data _null_;
        set mycities;
        city = macrocity;
        call execute('%createtablecity('||city||')');
    run;
    
proc sql noprint;
select quote(city_varname) into :cities separated by ',' from myCities;
quit; 

*上面的这一步创建了一个列表作为宏变量,以与下面的 in() 运算符一起使用。编辑:根据 Joe 的评论,添加了 quote() 函数,以便每个城市都将进入引号内的宏变量列表,以供下面的 in() 运算符正确引用。

create table all_cities as 
select * from connection to myDatabase 
(select * from mainTable 
where city in (&cities));

*这一步只是您在问题中提供的步骤,稍作修改以将 in() 与上面定义的宏变量列表一起使用。

一个相对简单的解决方案是完全一个数据步骤中完成。假设您可以通过 libname 连接(如果您可以通过 connect to 连接,您可能可以),假设 libname 是 mydb。第一部分使用与 Max Power 类似的结构:

proc sql noprint;
  select city_varname 
    into :citylist separated by ' ' 
    from myCities;
  select cats('%when(var=',city_varname,')') 
    into :whenlist separated by ' '
    from myCities;
quit; 

%macro when(var=);
  when "&var." output &var.;
%mend when;


data &citylist.;
  set mydb.mainTable;
  select(city);
    &whenlist.;
    otherwise;
  end;
run;

如果您正在使用 mainTable 中的大部分数据,这可能不会比在数据库端执行它慢多少,因为无论如何您都在移动所有数据 - 并且可能会更快,因为你只访问了一次数据库。

更好的方法是将它拉到一个 table(如 Max 所示),但如果您确实需要创建多个 table,这是一种合理的方法。

确实与这里的其他解决方案类似,也许更简单一些...拉出一个不同的城市列表,放入宏中,运行 SQL 在 do 循环中查询。

Proc sql noprint;
  Select distinct city, count(city) as c
  Into :n1-:n999, :c
  From connection to mydb
  (Select *
   From mainTable)
;
 Quit;

%macro createTables;

%do a=1 %to &c;

Proc sql;
  Create table &&n&a as
  Select  *
  From connection to myDb
  (Select *
   From mainTable
   Where city="&&n&a")
;
 Quit;

%end;

%mend createTables;

%createTables;