2

我正在使用 Oracle 11g。

我有 2 个相关表:存储值 (A) 和要插入的新值 (B)。两者都通过 3 列(客户端、组和人员代码)的 id 相关联。每个表有大约 20 个其他列(我们称它们为属性)。

我必须匹配它们,这样我才能知道哪些值是新的(B 中的 ID 而不是 A 中的),所以我将它们插入 A,它们是相等的(B 中的 ID 和 A 中具有相同属性),哪些不在新值(A 中的 id 但不再 B 中的 id),所以我从存储的值 (A) 中删除它们。

例如:

A:

客户 | 集团 | 个人代码 | 姓名 | 姓
_________________________________________________
1 | 1 | 1 | 乔 | 母鹿
1 | 1 | 2 | 卡尔 | 约翰
1 | 1 | 3 | 约翰 | 约翰

乙:

客户 | 集团 | 个人代码 | 姓名 | 姓
_________________________________________________
1 | 1 | 1 | 乔 | 母鹿
1 | 1 | 3 | 约翰 | 约翰
1 | 1 | 4 | 玛丽 | 骗局

在这个例子中,第 4 个人是新的,第 2 个人应该被删除,第 1 和第 3 个人保持不变。

所以,我需要一个返回以下结果的查询:

客户 | 集团 | 个人代码 | 行动
________________________________________
1 | 1 | 1 | 平等的
1 | 1 | 2 | 消除
1 | 1 | 3 | 平等的
1 | 1 | 4 | 新的

我所做的是以下查询:

   WITH 
   A AS (
    -- select from A table
   ), 
   B AS
   (
       -- select from B table
   ),     
   delete AS 
   (
    -- select from A WHERE NOT EXISTS (B.id = A.ID)
   ),       
   news AS 
   (
    -- select from B WHERE NOT EXISTS (A.id = B.ID)
   ),
   eq AS 
   (
    -- select A.* from A, B WHERE A.id = B.id AND A.attributes = B.attributes
   ) 
   select action.client, action.group, action.personcode, 'remove' from delete action
   UNION ALL
   select action.client, action.group, action.personcode, 'new' from news action
   UNION ALL
   select action.client, action.group, action.personcode, 'equal' from eq action
   ;

问题是,尽管这 3 个 last 选择中的每一个都在不到 10 秒的时间内运行,但当我使用UNIONor合并它们时UNION ALL,即使 delete 或 new 或 equal 为空,完整的查询也会持续大约 90 秒。A 或 B 中的行数可能超过 3000 行。

有没有办法以更好、更快的方式获得这个结果?

4

3 回答 3

4

您可以外连接表以生成它们之间差异的日志。

select coalesce(a.id,b.id) id,
       case when a.id is null
              then 'new'
            when b.id is null
              then 'remove'
            when a.col1 = b.col1 and a.col2 = b.col2 ...
              then 'same'
            else 'different'
        end
from    a full outer join b on (a.id = b.id)
于 2012-12-13T12:49:01.970 回答
2

如果表 B 有您想要的数据,为什么不使用该表而不是表 A 中的数据?创建一个同义词,指向其中包含正确数据的同义词并引用该同义词。

于 2012-12-13T11:42:11.733 回答
0

嗯,谢谢大家的回复。我终于做了一个视图,我使用这个博客中描述的策略传递了一些参数来过滤前两个查询 。完整的过程现在持续 30 秒,如果 A 或 B 没有行,则为 0(之前,它始终持续 90 秒)。这是对我当前程序影响较小的解决方案。

于 2012-12-14T12:31:33.530 回答