Tartaglia 的答案相当接近,但一步完成可能更容易。
data x1 x2;
merge x(in=x) a(in=found keep=id) b(in=found keep=id) c(in=found keep=id);
by id;
if x and found then output x1;
else if x then output x2;
run;
确保 'found' 和 'x' 不是任何原始数据集上的变量,否则使用其他
变量 如果你这样做了,那么如果你有多个匹配场景,那么你需要弄清楚如何确保你得到正确的变量。还需要对所有四个表进行排序(可能很慢)。
另一个 SAS 解决方案:哈希表。这不需要对数据集进行排序。如果您的数据集尚未按顺序排列,这可能会更快。但是,它确实需要足够的内存来将所有表 a、b 和 c 存储在内存中,这可能会受到这些数据集大小的限制;并且当 a,b,c 相对于 x 较小而不是它们具有相似大小时更好。可以使用defineData对其进行操作以从a / b / c产生数据而不仅仅是返回代码,但是如果在a,b,c中的两个(或三个都)。
data abc/view=abc;
set a b c;
keep id;
run;
data x1 x2;
if _n_ = 1 then do;
declare hash abc(dataset:"abc");
abc.defineKey("id");
abc.defineDone();
call missing(id);
end;
set x;
rc = abc.find();
if rc=0 then output x1;
else output x2;
run;
要在 oracle 中做到这一点,我想我会做一些更接近 tartaglia 解决方案的事情 - 创建三个“匹配”表,然后将它们合并(删除联合中的重复项),然后创建 x2 作为 x 减x1 表。IE(这在 SAS 中的 PROC SQL 中有效,不确定 oracle 是否完全相同):
create table x1 as
select x.* from x,a where x.id=a.id
union
select x.* from x,b where x.id=b.id
union
select x.* from x,c where x.id=c.id
;
create table x2 as
select * from x except select * from x1;
我使用 SAS 测试了这些(包括 SQL 解决方案,Oracle 可能更擅长但应该是类似的顺序 - 尽管如果您的 oracle 服务器比您的 sas 服务器更快,这可能会改变一些事情)。
使用具有 5e7 条记录的数据集“x”和具有公平重叠的三个数据集“a”“b”“c”(可能 25% 左右的记录在 2 个或更多数据集中,84% 在一个或多个数据集中)和每条记录在 1.5e7 和 3e7 之间(具体来说,一个全是奇数,一个是 3 的倍数,一个是 4 的偶数倍数),SQL 解决方案在排序和合并时需要 5 分钟以上的时间来处理解决方案排序大约需要 2.5 分钟,合并大约需要 0.5 分钟,因此总共大约需要 3 分钟。这可能有点夸张,因为数据集是按排序创建的,因此排序本身可能会更快一些(尽管 SQL 也会从有序的数据集中获得一些收益)。
相比之下,5e7 数据集 x 的写出时间约为 5 秒。
哈希解决方案不适合我的笔记本电脑上的内存,整个 ~6e7 记录数据集 abc,所以我将它们缩小到总共 ~2e7(所以几率从 1 到 2e7,然后是 3 的倍数从 2e7 到 4e7,然后是从 4e7 到 6e7 的 4 的倍数),但剩下的 x 中有 5e7 条记录。然后哈希解决方案总共花费了 1:41,而排序和合并解决方案花费了相似的时间,其中大部分是对 x 进行排序(大约一分钟)并合并/写出结果数据集(大约半分钟) . 这比对较大数据集进行排序要快得多,因为较小的数据集在内存中排序,而较大的数据集则不能。使用这些数据集的 SQL 解决方案大约需要 4 分钟,因此仍然慢得多。