比较同一个表中的SQL行,并在存在差异时打印出来

时间:2017-01-31 18:21:54

标签: sql oracle

我有一张桌子

userid | name |      email       |  address 
-------+------+------------------+-----------
1      | joe  |  joe@gmail.com   |  123 Road 
1      | joe  |  joe@gmail.com   |  null
1      | joe  |     null         |  null 

我希望每次更改用户以及更改哪一行时都返回一行。所以

Userid  |   change   
--------+-----------
  1     |   added address
  1     |   added email

如果一次改变了两件事,我想要改变'列包括两者。

目前我正在做这样的事情

SELECT 
   CASE WHEN table1.email <> table2.email THEN 'Email Change'
        WHEN table1.email IS NULL AND table2.email IS NOT NULL THEN 'Email addition' 
END email,
CASE WHEN table1.address <> table2.address THEN 'Address Change'
        WHEN table1.address IS NULL AND table2.address IS NOT NULL THEN 'Address addition' 
END address
FROM usertable table1 JOIN usertable table2 ON table1.userid = table2.userid

比较每一栏。然后我将在另一个选择中连接电子邮件和地址以供显示。

想知道是否有更高效的东西,因为我将比较大量的列。可以在这里申请LAG吗?

由于系统限制,我无法使用SP或任何类型的循环。使用oracle。这里有什么想法?

提前致谢!

1 个答案:

答案 0 :(得分:3)

这是我怎么做的。 (OP已经有了他的答案,但也许这将有助于未来的读者。)在每个属性的单独列中显示信息似乎要好得多 - 如果真的需要用于报告目的,它们可以连接在一起。我之前展示的格式更灵活 - 它允许查看用户有多少名称更改,以及电子邮件更改的数量。

with
     base_table ( userid, eff_dt, name, email, address ) as (
       select 1, date '2015-10-22', 'joe', 'joe@gmail.com', '123 Road' from dual union all
       select 1, date '2016-03-20', 'joe', 'joe@gmail.com', null       from dual union all
       select 1, date '2016-09-01', 'joe', null           , null       from dual
     )
select userid, eff_dt, name, email, address,
       case when lag(name) over (partition by userid order by eff_dt) is null
                 and name is not null then 'added'
            when lag(name) over (partition by userid order by eff_dt) is not null
                 and name is null     then 'deleted'
            when lag(name) over (partition by userid order by eff_dt) != name
                                      then 'updated'              end as name_changes,
       case when lag(email) over (partition by userid order by eff_dt) is null
                 and email is not null then 'added'
            when lag(email) over (partition by userid order by eff_dt) is not null
                 and email is null     then 'deleted'
            when lag(email) over (partition by userid order by eff_dt) != email
                                       then 'updated'             end as email_changes,
       case when lag(address) over (partition by userid order by eff_dt) is null
                 and address is not null then 'added'
            when lag(address) over (partition by userid order by eff_dt) is not null
                 and address is null     then 'deleted'
            when lag(address) over (partition by userid order by eff_dt) != address
                                         then 'update             end as address_changes
from   base_table
;

<强>输出

USERID EFF_DT     NAME EMAIL         ADDRESS  NAME_CHANGES EMAIL_CHANGES ADDRESS_CHANGES
------ ---------- ---- ------------- -------- ------------ ------------- ---------------
     1 2015-10-22 joe  joe@gmail.com 123 Road added        added         added
     1 2016-03-20 joe  joe@gmail.com                                     deleted
     1 2016-09-01 joe                                      deleted

 3 rows selected.