2016-12-19 2 views
0

У меня есть две похожие таблицы (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  

Мне было интересно, если t вот лучший и более эффективный способ узнать, какая запись и столбец были изменены без использования триггеров или любых других 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

Это звучит как простой случай использования для аудита стол управляется триггерами. –

+0

Привет @DrazenBjelovuk, я бы хотел сделать это без триггеров, только через Запросы, поскольку это только для целей исследования данных. Есть предположения? –

ответ

2

Вариация на тему ... Проблема решена много лет назад на AskTom, кредит Марко Стефанелли, который придумал основную идею.

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) - это будет 1, если employee_number появляется в одной таблице, но не в другом, поэтому в предложении 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 
; 
Смежные вопросы