具有组功能的 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 记录,其中area01。那么,您将如何确定具有该区域的两个 branch_cp 行中的每一个的两个 branch_code 值中的哪一个?你说过你想分组,但你需要说明你想要什么 - 最小或最大代码?两条记录将获得相同的值,这将违反您的主键。 好的。我想更新 area 01branch 01branch_cp 将通过 area 01branch 03branch_cp_2 更新。下一个 area 01branch 02branch_cp 将更新 area 01branch 04branch_cp_2。有没有可能!! 两个表中每个区域的记录数是否始终相同? 【参考方案1】:

您在每个表中有两条记录,其中area01,您需要将它们设置为不同的值以满足主键 - 您不能将它们都设置为第二个的最大值或最小值表,所以你真的不想做任何分组。

在具有相同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           

现在您实际上并不需要所有这些列,您只需要ridbranch_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 保持当前值”?

oracle 中plsql 怎样写更新一行的语句(高手请进)

oracle 更新语句 插入语句

oracle11g中有执行语句和执行脚本,有啥区别?

oracle中print_table存储过程实例介绍

在oracle sql语句里有没有if...else...的用法,请各位大侠给个例子看看,灰常感谢!!