1

我有 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 数据集。

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

问候,

4

2 回答 2

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' 不是任何原始数据集上的变量,否则使用其他 变量 如果你这样做了,那么如果你有多个匹配场景,那么你需要弄清楚如何确保你得到正确的变量。还需要对所有四个表进行排序(可能很慢)。

另一个 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 分钟,因此仍然慢得多。

于 2012-12-27T14:36:01.353 回答
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 重复此操作,如果与数据集 B 和 C 的匹配规则不同,则更改byand语句。还要更改 and 的名称等,这样它们就不会被覆盖。keepx1_ax2_ax1_b

附加所有x1_表格,您就拥有了X1问题中描述的数据集(您可能必须处理重复项)。

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

于 2012-12-27T14:25:23.080 回答