使用 proc sql 将具有迭代值的新列插入 table 中的每个唯一行

Insert new column with iterative value to every unique rows in a table using proc sql

我可以知道是否有技术可以将具有迭代值的新列插入 table 中的每个唯一行吗?

示例:

TABLE 有

ID  name
1   John
2   Matt
3   Pete

现在,我有一个计数器 = 3,我想将每个计数器值最多添加 3 到 table HAVE 中的每个唯一 ID。

TABLE 想要

ID name count
1  John 1
1  John 2
1  John 3
2  Matt 1
2  Matt 2
2  Matt 3
3  Pete 1
3  Pete 2
3  Pete 3

我可以使用 by 和 first.var:

的组合使用数据步骤来做到这一点
data want;
  set have;
    by ID;
  if first.ID then do;
    do i = 1 to count;
      output;
    end;
  end;
run;

我这里的主要问题是 运行时间,数据步按顺序处理数据集,可能需要一些时间才能 运行。我想知道这是否可以使用 proc sql 来完成?

使用内置功能proc sql无法特别轻松地做到这一点。一种解决方案是,如果您有某种计数或数字 table。那么你可以这样做:

select id, t.name, n.n
from t join
     numbers n
     on n.n <= :counter;

事实上,如果您的 ID 是连续的且没有间隙(如您的示例所示),您可以使用自连接:

select t.id, t.name, n.id as count
from t join
     t n
     on n.id <= :counter;

如果你知道具体值,你可以构造一个union all查询:

select id, name, 1 as count from t
union all
select id, name, 2 as count from t
union all
select id, name, 3 as count from t;

现代 SQL 现在具有简化此过程的构造(例如 window 函数和递归 CTE)。但是,这些不能直接在 proc sql.

中使用

结果集是外连接,如果有 N 行都不同,则将包含 N2 行。

示例:

SASHELP.CLASS 有 19 个不同的行,每行将有 18 个重复,得到 19**2 或 361 行。

帮助程序查询创建一个仅包含 count 值的帮助程序 table(我称它们为 index

data class;
  set sashelp.class;
run;

proc sql; 
* monotonic() trusted by Richard for this create/select only ;
* commented out for fear of mono (pun intended);
* create table indexes as 
  select index from
  ( select distinct *, monotonic() as index from class);

  * one mark per distinct row;
  create table distinct_marks(keep=mark) as
  select distinct *, 1 as mark from class;

* create table of traditionally computed monotonic indexes;
data indexes(keep=index);
  set distinct_marks;
  index + 1;
run;

proc sql;
  create table want as
  select 
    self.*, 
    each.index 
  from 
    class as self 
  cross join 
    indexes as each
  ;
quit;

将以上方法与您原来的方法进行比较

proc sql noprint;
  select count (*) into :count trimmed
  from 
  ( select distinct * from class );
quit;

data want;
  set class;
  do _n_ = 1 to &count;
    output;
  end;
run;```

Regardless of what approach you choose, OUTER JOINS can get BIG QUICK, and thus cause lots of time consuming disk i/o.