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', ...)));
我正在使用 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', ...)));