Summation/counting 在 sql 中按 id 分组的重叠值或日期

Summation/counting over overlapping values or dates with group by over id's in sql

我正在使用 sas table 并且日期表示为列 "entered" 和 "left" 中给出的数字。我必须计算该成员留在系统中的天数。例如下面的 id 1,该人在 7071 上输入并在 7075 上再次使用不同的产品,尽管他从 7071 到 7083 一直在系统中。这就是日期重叠。我想计算一个成员在系统中停留的最终持续时间,就像 id 1 一样,它是 12 天(7083-7071)+ 2 天(7087 到 7089)+ 4 天(7095 到 7099)。所以总共是18天。 (有一些重复的输入值和左值,但其他列(此处未显示)不相同,因此未删除这些行。)。因为我在 sas 工作所以这个想法可以是 sas 数据或 sas-sql 格式。

对于成员 2,没有值重叠。所以天数是 2(8921 到 8923)+ 5 天(8935 到 8940)= 7 天。我能够解决这种情况,因为日子没有重叠,但对于重叠情况,任何建议或 code/advice 表示赞赏。

id  Entered  left
 1    7071   7077
 1    7071   7077
 1    7075   7079
 1    7077   7083
 1    7077   7083
 1    7078   7085
 1    7087   7089
 1    7095   7099
 2    8921   8923
 2    8935   8940

所以最后的 table 应该是

的形式
id  days_in_system
 1       18
 2       7

这是一个非常棘手的问题,因为必须将每一行与其他每一行进行比较以获得相同的 ID 以检查重叠,如果有多个重叠,你必须非常小心,不要重复计算它们。

这是一个基于散列的解决方案 - 这个想法是建立一个散列,其中包含一个成员在您进行时停留的所有个人天数,然后在最后计算其中的项目数:

data have;
input id  Entered  left;
cards;
 1    7071   7077
 1    7071   7077
 1    7075   7079
 1    7077   7083
 1    7077   7083
 1    7078   7085
 1    7087   7089
 1    7095   7099
 2    8921   8923
 2    8935   8940
 ;
 run;

data want;

length day 8;
if _n_ = 1 then do;
  declare hash h();
  rc = h.definekey('day');
  rc = h.definedone();
end;

do until(last.id);
  set have;
  by id;
  do day = entered to left - 1;
    rc = h.add();
  end;
end;

total_days = h.num_items;
rc = h.clear();
keep id total_days;

run;

这应该不会占用太多内存,因为它一次只需加载 1 个 ID 的日期。

id 1 的输出是 20,而不是 18 - 这是我通过添加一些调试逻辑生成的逐行添加的新日期的细分。如有错误,请注明出处:

_N_=1
7071 7072 7073 7074 7075 7076
_N_=2
No new days
_N_=3
7077 7078
_N_=4
7079 7080 7081 7082
_N_=5
No new days
_N_=6
7083 7084
_N_=7
7087 7088
_N_=8
7095 7096 7097 7098
_N_=1
8921 8922
_N_=2
8935 8936 8937 8938 8939

如果您只想为符合特定条件的行添加天数,您可以在 set 语句中使用 where 子句来选择那些天数,例如

  set have(where = (var1 in ('value1', 'value2', ...)));