PL/SQL 切换两个表中的两列
PL/SQL Switching two columns from two tables
假设我有两个 table(tblA 和 tblB)并且想要切换每个 table(tblA.Grade 和 tblB.Grade)的第二列,如下所示:
+-------------------------------------+
| table a table b |
+-------------------------------------+
| name grade name grade |
| a 60 f 50 |
| b 45 g 70 |
| c 30 h 90 |
+-------------------------------------+
现在,我想将成绩栏从 table a 切换到 table b,并将成绩栏从 table b 切换到 table a。结果应如下所示:
+-----------------------------------------+
| table a table b |
+-----------------------------------------+
| name grade name grade |
| a 50 f 60 |
| b 70 g 45 |
| c 90 h 30 |
+-----------------------------------------+
我创建了 tables,使用批量收集将它们加载到游标中,并使用以下代码完成转换:
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;
所以,虽然我完成了任务,但我想知道是否有更简单的解决方案我没有想到?
如果有人知道是否有更简单的解决方案,请告诉我?
请注意,数据库中没有名为 first
或 second
的记录,因为无法保证第一个输入的记录将是第一个返回的记录。所以应该总是有一个 order by
来决定 first/second 等等
因此假设您希望记录按 name
排序,然后将第一个名字最小的等级 table 与第二个最小名字的等级 table,[=21 交换=]
现在假设您修复了现有代码中的顺序问题,并且如果它正常工作,我相信它会比我在下面执行的方法更快。像
- 创建一个临时文件 table 并按姓名顺序放置姓名和成绩。
之所以使用临时table主要是因为以后如果我想更正或还原数据,我可以使用相同的临时table来反转合并。
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;
如果对结果满意,稍后再降低温度table
drop table tmp1;
假设我有两个 table(tblA 和 tblB)并且想要切换每个 table(tblA.Grade 和 tblB.Grade)的第二列,如下所示:
+-------------------------------------+
| table a table b |
+-------------------------------------+
| name grade name grade |
| a 60 f 50 |
| b 45 g 70 |
| c 30 h 90 |
+-------------------------------------+
现在,我想将成绩栏从 table a 切换到 table b,并将成绩栏从 table b 切换到 table a。结果应如下所示:
+-----------------------------------------+
| table a table b |
+-----------------------------------------+
| name grade name grade |
| a 50 f 60 |
| b 70 g 45 |
| c 90 h 30 |
+-----------------------------------------+
我创建了 tables,使用批量收集将它们加载到游标中,并使用以下代码完成转换:
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;
所以,虽然我完成了任务,但我想知道是否有更简单的解决方案我没有想到?
如果有人知道是否有更简单的解决方案,请告诉我?
请注意,数据库中没有名为 first
或 second
的记录,因为无法保证第一个输入的记录将是第一个返回的记录。所以应该总是有一个 order by
来决定 first/second 等等
因此假设您希望记录按 name
排序,然后将第一个名字最小的等级 table 与第二个最小名字的等级 table,[=21 交换=]
现在假设您修复了现有代码中的顺序问题,并且如果它正常工作,我相信它会比我在下面执行的方法更快。像
- 创建一个临时文件 table 并按姓名顺序放置姓名和成绩。
之所以使用临时table主要是因为以后如果我想更正或还原数据,我可以使用相同的临时table来反转合并。
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;
如果对结果满意,稍后再降低温度table
drop table tmp1;