我有两个相似的表(Table_A和Table_B),它们共享相同的唯一标识符(Column 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
谢谢!
答案 0 :(得分:2)
主题的变化......许多年前在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
),请添加另一个&#34;列&#34;中间select
,count(*) over (partition by employee_number)
- 如果employee_number
出现在一个表中而不出现在另一个表中,则该值为1,因此在外部查询的where
子句中要求此号码为= 2
。
一个更简单的版本(更难以#34; hack&#34;排除那些在另一个表中没有匹配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
;