PL / SQL从两个表中切换两列

时间:2017-06-04 04:28:13

标签: oracle plsql bulk-load

假设我有两个表(tblA和tblB)并且想要切换每个表的第二列(tblA.Grade和tblB.Grade),如下所示:

+-------------------------------------+
|    table a               table b    |
+-------------------------------------+
| name  grade           name    grade |
| a     60              f       50    |
| b     45              g       70    |
| c     30              h       90    |
+-------------------------------------+

现在,我想将等级列从表a切换到表b,将等级列从表b切换到表a。结果应如下所示:

+-----------------------------------------+
|      table a               table b      |
+-----------------------------------------+
|     name  grade           name    grade |
|     a     50              f       60    |
|     b     70              g       45    |
|     c     90              h       30    |
+-----------------------------------------+

我创建了表,使用批量收集将它们加载到游标中,并使用以下代码完成转换:

insert into tblA values('a',60);
insert into tblA values('b',45);
insert into tblA values('c',30);
insert into tblb values('f',70);
insert into tblb values('g',80);
insert into tblb values('h',90);

DECLARE
    TYPE tbla_type IS TABLE OF tbla%ROWTYPE;
    l_tbla tbla_type;
    TYPE tblb_type IS TABLE OF tblb%ROWTYPE;
    l_tblb tblb_type;

BEGIN
-- All rows at once...
SELECT *
BULK COLLECT INTO l_tbla
FROM tbla;

SELECT *
BULK COLLECT INTO l_tblb
FROM tblb;

    DBMS_OUTPUT.put_line (l_tblb.COUNT);

    FOR indx IN 1 .. l_tbla.COUNT
  LOOP
    DBMS_OUTPUT.put_line (l_tbla(indx).lname);
        update tbla set grade = l_tblb(indx).grade 
          where l_tbla(indx).lname= tbla.lname;

              update tblb set grade = l_tbla(indx).grade 
          where l_tblb(indx).lname= tblb.lname;
  END LOOP;
END;

所以,虽然我完成了任务,但我想知道是否有一个我没想过的更简单的解决方案?

如果有人知道是否有更简单的解决方案,请告诉我?

1 个答案:

答案 0 :(得分:3)

请注意,数据库中没有任何名为firstsecond的记录,因为无法保证输入的第一条记录将是返回的第一条记录。因此,总是应该有order by来决定第一个/第二个等等。

因此,假设您希望记录按name排序,然后将第一个表的最小名称等级与第二个表的最小名称等级交换,

现在假设您在现有代码中修复了订单,如果它正在运行,我相信它会比我在下面的方式更快。像

这样的东西
  1. 创建临时表并按名称排序名称和等级。
  2. 使用临时表的原因主要是因为以后如果我想更正或恢复数据,我可以使用相同的临时表来反转合并。

        create table tmp1 as
        with ta as
        (select t.* ,
        row_number() over (order by name) as rnk
        from tblA t)
        ,tb as
        (select t.* ,
        row_number() over (order by name) as rnk
        from tblb t)
        select ta.name as ta_name,ta.grade as ta_grade,
        tb.name as tb_name,tb.grade as tb_grade
        from ta inner join tb
        on ta.rnk=tb.rnk
    

    tmp1

    的输出
    +---------+----------+---------+----------+
    | TA_NAME | TA_GRADE | TB_NAME | TB_GRADE |
    +---------+----------+---------+----------+
    | a       |       60 | f       |       70 |
    | b       |       45 | g       |       80 |
    | c       |       30 | h       |       90 |
    +---------+----------+---------+----------+
    

    然后使用merge来交换tmp1的值。

    merge  into tbla t1
    using  tmp1 t
    on (t1.name=t.ta_name)
    when matched then update
    set t1.grade=t.tb_grade;
    
    merge  into tblb t1
    using  tmp1 t
    on (t1.name=t.tb_name)
    when matched then update
    set t1.grade=t.ta_grade;
    

    如果对结果满意,请稍后删除临时表

    drop table tmp1;