【问题标题】:Find differences between two large tables in oracle在oracle中查找两个大表之间的差异
【发布时间】:2014-01-12 02:25:49
【问题描述】:

我有两个不同的表,比如 oracle 中的表 A 和 B,每个表大约有 1500 万条记录。 Table A 具有列 (a,b,c,d)Table B 有列 (e,f,g,h)

目标是编写一个存储过程来检查表 A 中存在的每条记录是否也存在于表 B 中,反之亦然。应该将这两者之间的差异插入到第三个表中。

我的问题是 如果column e 包含某个字符串(0311),则Table A 中的column a 应与表B 中的e 列和f 列的连接进行比较, 如果不是,我必须将其与 column f 进行比较。

Column b 应该与table B 中的column g 和 我还必须将table A 中的column ctable B 中的column g 进行比较,如果两者不匹配,则column d 应与column g 进行比较。

最快的方法是什么?

例如这两个是匹配的:

Table A: 9353456789,03117884657,12082200003035,12082123595535
Table B: 9353456789,0311,7884657,12082200003035

或:

Table A: 9353456789,03117884657,12082200003035,12082123595535
Table B: 9353456789,0311,7884657,12082123595535

不需要连接且匹配的记录示例:

Table A: 9353456789,03617884657,12082200003035,12082123595535
Table B: 9353456789,0361,03617884657,12082200003035

【问题讨论】:

  • 一般来说,您可以使用以下查询找到tableA 中但不在tableB 中的行(假设结构相同/相似):SELECT * FROM tableA MINUS SELECT * FROM tableB。对于您的问题,尽管我们需要更多详细信息 - 您能否发布一个 3-4 TableA 行和 3-4 TableB 行的示例,包括至少一个将强制通过连接值进行比较的行?
  • 是的,例如这两个是匹配的:表A:9353456789,03117884657,12082200003035,12082123595535 表B:9353456789,0311,7884657,12082200003035
  • 抱歉,这还不够。您能否为每个场景至少包含一组行(连接与不连接),您是否还可以识别列abc、...g。另外,请指定e 列必须包含的“特定字符串”。如果您编辑您的问题并添加示例而不是在评论中发布它们,那将是最好的。我敢肯定,只要定义得足够好,您的问题就可以得到解答。
  • 我的猜测是用户自己会找到答案,如果他能够解释他的要求。请帮助我们,为您提供帮助!

标签: sql database oracle plsql large-data


【解决方案1】:

SQL Fiddle

Oracle 11g R2 架构设置

CREATE TABLE TableA ( a VARCHAR2(20), b VARCHAR2(20), c VARCHAR2(20), d VARCHAR2(20) );
CREATE TABLE TableB ( e VARCHAR2(20), f VARCHAR2(20), g VARCHAR2(20), h VARCHAR2(20) );
CREATE TABLE TableC ( i VARCHAR2(20), j VARCHAR2(20), k VARCHAR2(20), l VARCHAR2(20) );

INSERT INTO TableA
          SELECT '9353456789','03117884657','12082200003035','12082123595535' FROM DUAL
UNION ALL SELECT '9353456789','03617884657','12082200003035','12082123595535' FROM DUAL
UNION ALL SELECT '9353456789','03617884657','12082200003034','12082123595534' FROM DUAL;

INSERT INTO TableB
          SELECT '9353456789','0311','7884657','12082200003035' FROM DUAL
UNION ALL SELECT '9353456789','0311','7884657','12082123595535' FROM DUAL
UNION ALL SELECT '9353456789','0361','03617884657','12082200003035' FROM DUAL
UNION ALL SELECT '9353456789','0361','03617884657','12082200003036' FROM DUAL;

查询 1

要插入行 - 在两个表之间使用FULL OUTER JOIN 执行INSERT INTO... SELECT,使用您的要求作为连接条件;那么对于不匹配TableA(a, b, c, d) 的行将全部为NULLTableB(e, f, g, h) 将全部为NULL,这可以在WHERE 条件中使用以仅获取不匹配的行。最后,为了不返回NULL值,返回值使用COALESCE()

INSERT INTO TableC
    SELECT COALESCE( ta.a, tb.e ) AS i,
           COALESCE( ta.b, tb.f ) AS j,
           COALESCE( ta.c, tb.g ) AS k,
           COALESCE( ta.d, tb.h ) AS l
    FROM TableA ta
         FULL OUTER JOIN
         TableB tb
         ON (    ta.a = tb.e
             AND ta.b = CASE tb.f WHEN '0311' THEN tb.f || tb.g ELSE tb.g END
             AND ( ta.c = tb.h OR ta.d = tb.h )
            )
    WHERE ta.a IS NULL
    OR    tb.e IS NULL;

查询 2

SELECT * FROM TableC

Results

|          I |           J |              K |              L |
|------------|-------------|----------------|----------------|
| 9353456789 | 03617884657 | 12082200003034 | 12082123595534 |
| 9353456789 |        0361 |    03617884657 | 12082200003036 |

【讨论】:

    【解决方案2】:

    我会用两个语句来做,虽然它可以合并

    Select a.* 
    from tablea a left join tableb b on a.a = 
     case when e = 'string' then b.e || b.f else b.f end 
    and ...
    where b.e is null
    

    左连接将在表 b 中未找到行的情况下返回空值,因此这应该会显示表 a 中不在表 b 中的行列表。将语句更改为右连接并选择 b.*,您将看到 b 中的内容,但 a 中没有。

    语句可以转换为“create table as”,它将使用此 select 语句的结果创建一个新表。

    我说...你的条件有点混乱,你只需要使用 case 语句来选择你想要比较/加入的列。

    【讨论】:

    • 以及如何将结果导入另一个表?抱歉,我真的是 sql 新手。
    • 在 oracle 中很简单...将 CREATE TABLE new_table AS 将您的选择语句放在这里。这会将您的查询结果保存为 new_table(您可以更改使用该表的任何名称来代替 new_table)
    • 我做了一个快速编辑...在 Oracle 中连接是作为 field1 || field2(或 field1 || ' ' || field2 如果你想要两者之间的空间)
    猜你喜欢
    • 2013-02-26
    • 2015-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多