繁体   English   中英

找出两个表之间更新的记录和列

[英]Find out which Record and Column was Updated Between Two Tables

我有两个相似的表(Table_A和Table_B),它们共享相同的唯一标识符(Employee_Number列)。 他们也有类似的数据。

Create table Table_A
(
    Employee_Number varchar2(100),
    name            varchar2(100),
    address         varchar2(100),
    tel_no          varchar2(100),
    social_sec_no   varchar2(100)
);

INSERT INTO Table_A  (Employee_Number, name, address, tel_no, social_sec_no) values ('1', 'emp 1', 'home1', '1111', '11111');
INSERT INTO Table_A  (Employee_Number, name, address, tel_no, social_sec_no) values ('2', 'emp 2', 'home2', '2222', '22222');
INSERT INTO Table_A  (Employee_Number, name, address, tel_no, social_sec_no) values ('3', 'emp 3', 'home3', '3333', '33333');
INSERT INTO Table_A  (Employee_Number, name, address, tel_no, social_sec_no) values ('4', 'emp 4', 'home4', '4444', '44444');
INSERT INTO Table_A  (Employee_Number, name, address, tel_no, social_sec_no) values ('5', 'emp 5', 'home5', '5555', '55555');

commit;

create table Table_b
as
select  *
from    Table_A;

但是,表B的记录之一已更改:

update  Table_b
set     social_sec_no = '99999'
where   Employee_Number = '1';

update  Table_b
set     social_sec_no = 'xxxx'
where   Employee_Number = '3';

update  Table_b
set     address = 'office'
where   Employee_Number = '1';

commit;

这是我发现哪些列已更改的操作:

SELECT  *
FROM    (select AX.Employee_Number
              , CASE WHEN AX.name          <> bx.NAME          THEN 'CHANGED' else 'NO_CHANGE' END  name
              , CASE WHEN AX.address       <> bx.address       THEN 'CHANGED' else 'NO_CHANGE' END  address
              , CASE WHEN AX.tel_no        <> bx.tel_no        THEN 'CHANGED' else 'NO_CHANGE' END  tel_no
              , CASE WHEN AX.social_sec_no <> bx.social_sec_no THEN 'CHANGED' else 'NO_CHANGE' END  social_sec_no
        from    Table_A ax
              , Table_B bx
        where   ax.Employee_Number = bx.Employee_Number
        and    (ax.name          <> bx.name
        or      ax.address       <> bx.address
        or      ax.tel_no        <> bx.tel_no
        or      ax.social_sec_no <> bx.social_sec_no))
WHERE   1=1
AND    (name          = 'CHANGED'
OR      address       = 'CHANGED'
OR      tel_no        = 'CHANGED'
OR      social_sec_no = 'CHANGED');   

查询结果

Employee_Number NAME        ADDRESS     TEL_NO      SOCIAL_SEC_NO     
--------------- ---------   ---------   ---------   --------------
1               NO_CHANGE   CHANGED     NO_CHANGE   CHANGED
3               NO_CHANGE   NO_CHANGE   NO_CHANGE   CHANGED       

我想知道是否有更好,更有效的方法来找出在不使用触发器或任何其他DDL和DML的情况下更改了哪个记录和列?

数据库详细信息:

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production

谢谢!

一个主题的变体...问题在多年前就通过AskTom解决了,这归功于提出了核心思想的Marco Stefanelli。

select * 
from (
  select source, employee_number, name, address, tel_no, social_sec_no,
         count(*) over ( partition by employee_number, 
                       name, address, tel_no, social_sec_no) as cnt
  from (
         select 'table_a' as source, 
                employee_number, name, address, tel_no, social_sec_no
           from table_a
         union all
         select 'table_b' as source, 
                employee_number, name, address, tel_no, social_sec_no
           from table_b
       )
)
where cnt = 1
order by employee_number, source
;

SOURCE   EMPLOYEE_NUMBER NAME       ADDRESS      TEL_NO     SOCIAL_SEC_NO    CNT
-------  --------------- ---------- ------------ ---------- ------------- ------
table_a  1               emp 1      home1        1111       11111              1
table_b  1               emp 1      office       1111       99999              1
table_a  3               emp 3      home3        3333       33333              1
table_b  3               emp 3      home3        3333       xxxx               1

4 rows selected.

此查询还将识别一个表中在另一表中没有对应项的行(行具有相同的employee_number )。 它的工作方式是,如果两个表中都存在完全相同的行,则count(*)为2。

如果要排除一个表中的行而不是另一个表中的行(完全是-表示没有匹配的employee_number ),请在中间select添加另一个“列”,以使count(*) over (partition by employee_number)如果一个employee_number出现在一个表中而不出现在另一个表中,则将为1,因此在外部查询的where子句中,请将该数字设为= 2

一个简单的版本(虽然很难“破解”以排除其他表中没有匹配的employee_number的行):

select max(source) as source, 
       employee_number, name, address, tel_no, social_sec_no
from   (
         select 'table_a' as source, 
                employee_number, name, address, tel_no, social_sec_no
           from table_a
         union all
         select 'table_b' as source, 
                 employee_number, name, address, tel_no, social_sec_no
           from table_b
       )
group by employee_number, name, address, tel_no, social_sec_no
having count(*) = 1
order by employee_number, source
;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM