假设我有两个表(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;
所以,虽然我完成了任务,但我想知道是否有一个我没想过的更简单的解决方案?
如果有人知道是否有更简单的解决方案,请告诉我?
答案 0 :(得分:3)
请注意,数据库中没有任何名为first
或second
的记录,因为无法保证输入的第一条记录将是返回的第一条记录。因此,总是应该有order by
来决定第一个/第二个等等。
因此,假设您希望记录按name
排序,然后将第一个表的最小名称等级与第二个表的最小名称等级交换,
现在假设您在现有代码中修复了订单,如果它正在运行,我相信它会比我在下面的方式更快。像
这样的东西使用临时表的原因主要是因为以后如果我想更正或恢复数据,我可以使用相同的临时表来反转合并。
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;