来自多个表/数据集的Oracle / SAS记录匹配

时间:2012-12-27 01:54:13

标签: oracle sas

我有4张非常大的桌子。我叫他们叫X,A,B和C.

我想从X创建另外两个表X1和X2,如下所示:

考虑表X中的记录r。如果r在表A,B和C中的至少一个表中有相应的记录,我将它放在X1中。另外我把它放在X2中。

(我如何确定r在A,B或C中有相应的记录?我将r的几个字段与A,B或C中的记录的几个字段进行比较。字段可能与A不同, B或C并且可能有多个标准将r与A,B或C中的记录匹配。可能这部分与主要问题无关。)

我有两个选项:我可以将X,A,B和C作为Oracle表或SAS数据集。

解决此问题的最有效方法是什么?

此致

2 个答案:

答案 0 :(得分:1)

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'不是任何原始数据集上的变量,否则请使用其他内容 唯一复杂的因素是如果你想要a,b,c之外的一些变量而不是ID;如果你这样做,那么你需要弄清楚如果你有一个多重匹配场景,你如何确保获得正确的变量。还需要对所有四个表进行排序(可能很慢)。

另一种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 as 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的几率,然后从2e7的3的倍数)到4e7,然后从4e7到6e7的4的倍数,但是左边的x有5e7个记录。然后哈希解决方案总共花费了1:41,与排序和合并解决方案相比,花费了相似的时间,其中大部分是排序x(大约一分钟)并合并/写出结果数据集(大约一分钟) 。这比排序较大的数据集快得多,因为较小的数据集在内存中排序,而较大的数据集则不能排序。这些数据集的SQL解决方案大约需要4分钟,因此仍然要慢得多。

答案 1 :(得分:0)

如果我理解正确,你可以这样做:

在要查找的变量中合并数据集X和A. 从X输出记录形式A到X1的记录,并输出那些不匹配的记录 进入X2。

假设您正在处理示例数据集X和A:

data x;
input id some_value $;
datalines;
1 a
2 b
3 c
4 d
5 e
run;

data a;
input id some_value $ some_value_2 $;
datalines;
1 a x
4 d v
5 g u
run;

现在,您可以像这样进行合并:

data x1_a x2_a;
merge x(in=table_x) a(in=table_a keep=id some_value);
by id some_value;
if table_x = 1 and table_a = 1 then output x1_a;
if table_x = 1 and table_a = 0 then output x2_a;
run;

对数据集B和C重复,如果存在则更改bykeep语句 与数据集B和C匹配的不同规则。还将x1_ax2_a的名称更改为x1_b,依此类推,因此不会被覆盖。

附加所有x1_表,并在问题中提供X1数据集(您可能需要处理重复项)。

附加所有x2_表,并计算不同的行。出现的行数与 您要比较的初始数据集(本例中为3; A,B,C)是您保留的数据集。