具有组功能的 Oracle 更新语句
Posted
技术标签:
【中文标题】具有组功能的 Oracle 更新语句【英文标题】:Oracle update statement with group function 【发布时间】:2014-10-02 15:35:54 【问题描述】:我对带有 group 功能的 Oracle Update 语句有一些问题 我想从另一个表中更新一列的所有记录。 但它显示 SQL 错误:ORA-01427:单行子查询返回多于一行 这是我的例子。
create table branch_cp
(
area varchar2 (5) ,
branch_code varchar2 (5) primary key,
branch_name varchar2 (20));
------
create table branch_cp_2
(
area varchar2 (5) ,
branch_code varchar2 (5) primary key,
branch_name varchar2 (20));
----------------------------------
insert into branch_cp values ('01', '01', 'A');
insert into branch_cp values ('01', '02', 'B');
insert into branch_cp values ('03', '03', 'C');
----------
insert into branch_cp_2 values ('01', '04', 'D');
insert into branch_cp_2 values ('01', '05', 'E');
insert into branch_cp_2 values ('03', '06', 'F');
----------------------
select * from branch_cp;
------------------
update branch_cp
set branch_cp.branch_code = (select branch_cp_2.branch_code
from branch_cp_2
where branch_cp.area =branch_cp_2.area)
where exists (select 1 from branch_cp_2 where branch_cp_2.area = branch_cp.area) ;
如何在更新语句中使用组函数。请帮忙
【问题讨论】:
area 是一个主键列 brach_cp_2 ,您的插入应该会失败,因为您插入相同的值 01 两次。 抱歉输入错误。分支是主键 嗯,你有两条branch_cp_2
记录,其中area
是01
。那么,您将如何确定具有该区域的两个 branch_cp
行中的每一个的两个 branch_code
值中的哪一个?你说过你想分组,但你需要说明你想要什么 - 最小或最大代码?两条记录将获得相同的值,这将违反您的主键。
好的。我想更新 area
01
和 branch
01
从 branch_cp
将通过 area
01
和 branch
03
从 branch_cp_2
更新。下一个 area
01
和 branch
02
从 branch_cp
将更新 area
01
和 branch
04
从 branch_cp_2
。有没有可能!!
两个表中每个区域的记录数是否始终相同?
【参考方案1】:
您在每个表中有两条记录,其中area
是01
,您需要将它们设置为不同的值以满足主键 - 您不能将它们都设置为第二个的最大值或最小值表,所以你真的不想做任何分组。
在具有相同area
的记录之间似乎没有任何其他排序,所以我假设它是任意的,每个area
的哪条记录从另一个branch_code
中获取哪个记录并不重要桌子。如果不是任意的,则需要指定规则...
如果您需要在一组记录中按任意顺序进行匹配,则相关更新会很棘手。您需要一些方法来识别行顺序,但在原始表中添加 row_number()
列以创建内联视图会导致 ORA-01732 错误。
不过,您可以使用目标表的 rowid
伪列;您只需在关联中进行额外的连接,即可获得与新的branch_code
相同的值。比如:
select bc.rid,
bc.area,
bc.branch_code,
bc.branch_name,
bc2.area,
bc2.branch_code,
bc2.branch_name
from (
select bc.*,
bc.rowid as rid,
row_number() over (partition by bc.area order by bc.branch_code) as rn
from branch_cp bc
) bc
join (
select bc2.*,
row_number() over (partition by bc2.area order by bc2.branch_code) as rn
from branch_cp_2 bc2
) bc2
on bc2.area = bc.area
and bc2.rn = bc.rn;
这给了你:
RID AREA BRANCH_CODE BRANCH_NAME AREA BRANCH_CODE BRANCH_NAME
------------------ ----- ----------- ----------- ----- ----------- -----------
AAAwy+AAEAAAA0DAAA 01 01 A 01 04 D
AAAwy+AAEAAAA0DAAB 01 02 B 01 05 E
AAAwy+AAEAAAA0DAAC 03 03 C 03 06 F
现在您实际上并不需要所有这些列,您只需要rid
(branch_cp.rowid
)和相关的branch_cp_2.branch_code
。
但您也只想在匹配时更新 - 以使其他表中没有值的任何行无效 - 因此您必须在 exists
子查询中重复该连接。
做一个merge
更简单:
merge into branch_cp bc
using (
select bc.rid,
bc2.branch_code
from (
select bc.*,
bc.rowid as rid,
row_number() over (partition by bc.area order by bc.branch_code) as rn
from branch_cp bc
) bc
join (
select bc2.*,
row_number() over (partition by bc2.area order by bc2.branch_code) as rn
from branch_cp_2 bc2
) bc2
on bc2.area = bc.area
and bc2.rn = bc.rn
) bc2
on (bc.rowid = bc2.rid)
when matched then update set bc.branch_code = bc2.branch_code;
3 rows merged.
您的桌子现在有:
select * from branch_cp;
AREA BRANCH_CODE BRANCH_NAME
----- ----------- -----------
01 04 A
01 05 B
03 06 C
SQL Fiddle.
【讨论】:
哇..非常感谢。这对我完全有帮助。我还尝试在两个表中添加一个新的匹配行。它有效。再次感谢。 :) @K_islam:如果它适合你,请接受这个答案。以上是关于具有组功能的 Oracle 更新语句的主要内容,如果未能解决你的问题,请参考以下文章
Oracle:有没有一种简单的方法可以在合并/更新语句中说“如果 null 保持当前值”?