合并两个模式表,包括也在Oracle中的从属表

时间:2019-02-27 16:41:55

标签: oracle plsql

我在架构abc中有3个表。它们是

user_data

user_addr

用户sal

在其他模式xyz中也可以使用相同的3个表。我们需要将xyz模式表合并为abc模式表。但条件是:

1)如果不存在用户ID,则插入。 2)如果userid已经存在并且其电子邮件ID不同,则插入记录,但在所有3个表中使用seq.next_value更新user_id。

例如:

在Abc模式中:

表user_date

user_id  name     email_id           date
1        gaurav    gav@gmail.com      21-01-2018

表user_add

user_id  addres       pin
1        GZB          325123

表use_sal

user_id   sal    effective date
1         25000   22-05-2018

在XYZschema中:

表user_date

user_id  name     email_id           date
1        Arun arun@gmail.com      25-01-2018
5        kk    kk@gmail.com       26-06-2018

表user_add

user_id  addres       pin
1        Noida        789546
5        HYD          564231

表use_sal

user_id   sal    effective date
1         35000   22-06-2018
5         45000   25-07-2018

所以,我需要模式abc中的最终输出是。如果序列的下一个值是100,那么

表user_date

user_id  name     email_id           date
1        gaurav    gav@gmail.com      21-01-2018
5        kk       kk@gmail.com       26-06-2018
100      Arun     arun@gmail.com      25-01-2018

表user_add

user_id  addres       pin
1        GZB          325123
5        HYD          564231
100      Noida        789546

表use_sal

user_id   sal    effective date
1         25000   22-05-2018
5         45000   25-07-2018
100       35000   22-06-2018

我只给出了一些记录的示例。表中有1000行。请提出如何获取此记录的建议。我们可以将架构abc中的xyz表作为xyz.user_data访问。

2 个答案:

答案 0 :(得分:0)

您可以尝试以下PL / SQL块

DECLARE 
    l_user user_data.user_id%TYPE;
    l_email user_data.email_id%TYPE;
BEGIN
  FOR i IN (SELECT d.user_id,d.name,d.email_id,d.jdate,a.addr,a.pin,s.sal,s.eff_date 
            FROM xyz.user_data d
            INNER JOIN xyz.user_addr a
            ON d.user_id=a.user_id
            INNER JOIN xyz.user_sal s
            ON d.user_id=s.user_id)
  LOOP
     BEGIN
        SELECT user_id,email_id
          INTO l_user,l_email
          FROM abc.user_data
         WHERE user_id=i.user_id;
     EXCEPTION
     WHEN NO_DATA_FOUND THEN
        l_user := NULL;
        l_email := NULL;
     END;
     IF l_user IS NULL THEN
         INSERT INTO abc.user_data VALUES
         (i.user_id,i.name,i.email_id,i.jdate);

         INSERT INTO abc.user_addr VALUES
         (i.user_id,i.addr,i.pin);

         INSERT INTO abc.user_sal VALUES
         (i.user_id,i.sal,i.eff_date);

     ELSIF l_user IS NOT NULL AND l_email != i.email_id THEN

        SELECT abc.userid.NEXTVAL INTO l_user FROM DUAL;

         INSERT INTO abc.user_data VALUES
         (l_user,i.name,i.email_id,i.jdate);

         INSERT INTO abc.user_addr VALUES
         (l_user,i.addr,i.pin);

         INSERT INTO abc.user_sal VALUES
         (l_user,i.sal,i.eff_date);
     END IF;
  END LOOP;
END;

答案 1 :(得分:0)

仅使用SQL的方法

由于对CURRVAL和NEXTVAL的限制,例如它们不能与DISTINCT,子查询或UNION等一起使用(请参见documentation),使用SQL解决问题有些棘手。这是一个使原始表保持完整的解决方案(经过Oracle 12c和11g测试)。步骤:

{1}通过联接“表集”的所有3个表来创建表(称为TEMP_),分别在结果表T1和T2中标记每一行。 UNION结果集。

{2}创建SEQUENCE。

{3}创建MASTER_表,其中包含每个唯一ID(第一次查询)的{a}行和ID多次出现的{b}行,并在NEWID列中填充序列中的值(以100000开始)这个例子)。

{4}通过从MASTER_中选择适当的列来创建3个新的明细表。

整理一下:放下TEMP_和MASTER _

-{1}

-- table TEMP_ contains unaltered data from _both_ table sets ( 2 x 3 tables )
-- multiple ID columns removed
-- short names for the original tables: 
-- ud -> user_data, ua -> user_addr, us -> user_sal
--
create table temp_
as
select 'TS1' as table_set
, ud1.user_id, ud1.name, ud1.email_id, ud1.date_
, ua1.address, ua1.pin
, us1.sal, us1.effective_date
from ud1 
  join ua1 on ud1.user_id = ua1.user_id 
  join us1 on ud1.user_id = us1.user_id 
union
select 'TS2' as table_set
, ud2.user_id, ud2.name, ud2.email_id, ud2.date_
, ua2.address, ua2.pin
, us2.sal, us2.effective_date
from ud2 
  join ua2 on ud2.user_id = ua2.user_id 
  join us2 on ud2.user_id = us2.user_id 
;

-{2}

create sequence uid_seq start with 100000 increment by 1 ;

-{3a}查找唯一ID(不需要.NEXTVAL)

-- column list should be coded (omitted here for clarity)
create table master_ as
select unique_ids.user_id as newid, unique_ids.*
from (
  select table_set
  , user_id, name, email_id, date_  -- table ud
  , address, pin                    -- table ua
  , sal, effective_date             -- table us
  , row_number() over ( partition by user_id order by table_set ) id_occurences
  from temp_ 
) unique_ids
where id_occurences = 1 ;

-{3b}找到重复的ID,然后按顺序替换。NEXTVAL

-- We cannot use UNION on the 2 resultsets {3a} and {3b} when creating the MASTER_ table,
-- due to the fact that we are using .NEXTVAL (for duplicate user_ids).
-- However, this 2-step approach works. (CTAS, and subsequent INSERT ... SELECT)
-- 
-- column list should be coded (omitted here for clarity)
insert into master_
select uid_seq.nextval as newid, duplicates.*
from (
  select table_set
--  , uid_seq.nextval  -- throws ORA-02287: sequence number not allowed here
  , user_id, name, email_id, date_  -- table ud
  , address, pin                    -- table ua
  , sal, effective_date             -- table us
  , row_number() over ( partition by user_id order by table_set ) id_occurences
  from temp_ 
) duplicates
where id_occurences > 1 
;

-{4}用来自MASTER_的数据填充新的“ part”表。

-- ud: "user_data"
create table udnew 
as 
select newid, name, email_id, date_ from master_ ;

-- ua: "user_add"
create table uanew 
as 
select newid, address, pin from master_ ;

-- us: "use_sal"
create table usnew 
as 
select newid, sal, effective_date from master_ ;

新表包含...

SQL> select * from udnew ;

     NEWID NAME   EMAIL_ID       DATE_    
---------- ------ -------------- ---------
         1 gaurav gav@gmail.com  21-JAN-18
         5 kk     kk@gmail.com   26-JUN-18
    100000 Arun   arun@gmail.com 25-JAN-18

SQL> select * from uanew ;

     NEWID ADDRE        PIN
---------- ----- ----------
         1 GZB       325123
         5 HYD       564231
    100000 Noida     789546

SQL> select * from usnew ;

     NEWID        SAL EFFECTIVE
---------- ---------- ---------
         1      25000 22-MAY-18
         5      45000 25-JUL-18
    100000      35000 22-JUN-18

测试数据和更多详细信息:请参见Dbfiddle

替代方法:使用SQL和PL / SQL

使用PL / SQL时,我们可以执行以下操作:{1}创建表“第二组”的副本,{2}创建所需的序列,{3}编写并执行更新已复制副本的过程{4}通过为“表集1”中的每个表编写并执行UNION来创建3个新表,并将它们与“表集2”中对应的(复制的)更新表结合起来,从而创建3个新表是。

-{1}创建表“第二组”的副本

create table ud2copy as select * from ud2 ;
create table ua2copy as select * from ua2 ;
create table us2copy as select * from us2 ;

-{2}创建所需的序列

create sequence uid_seq start with 100000 increment by 1 ;

-{3}过程,用于使用所需的.NEXTVALS更新复制的表

create or replace procedure updateIDs
is
begin
  for rec_ in (
    select uid_seq.nextval new_id, ud2copy.user_id
    from ud1 
      join ud2copy on ud1.user_id = ud2copy.user_id 
    where ud1.email_id <> ud2copy.email_id
  )
  loop
    update ud2copy set user_id = rec_.new_id where user_id = rec_.user_id ;
    update ua2copy set user_id = rec_.new_id where user_id = rec_.user_id ;
    update us2copy set user_id = rec_.new_id where user_id = rec_.user_id ;
  end loop;
end ;
/

begin
  updateIDs ;
  commit ;
end ;
/

-{4}创建3个新表

create table udnew as select * from ud1 union select * from ud2copy ;
create table uanew as select * from ua1 union select * from ua2copy ;
create table usnew as select * from us1 union select * from us2copy ;

结果:新表包含...

SQL> select * from udnew ;

   USER_ID NAME   EMAIL_ID       DATE_    
---------- ------ -------------- ---------
         1 gaurav gav@gmail.com  21-JAN-18
         5 kk     kk@gmail.com   26-JUN-18
    100000 Arun   arun@gmail.com 25-JAN-18

SQL> select * from uanew ;

   USER_ID ADDRE        PIN
---------- ----- ----------
         1 GZB       325123
         5 HYD       564231
    100000 Noida     789546

SQL> select * from usnew ;

   USER_ID        SAL EFFECTIVE
---------- ---------- ---------
         1      25000 22-MAY-18
         5      45000 25-JUL-18
    100000      35000 22-JUN-18

Dbfiddle here.

注释作者:这里没有BULK或FORALL操作...我们知道:此过程代码并不像它可能那样有效。但是,PL / SQL代码应该“足够快”,因为我们只处理数千行(每个表)。