Oracle:更新非唯一字段

Posted

技术标签:

【中文标题】Oracle:更新非唯一字段【英文标题】:Oracle: update non-unique field 【发布时间】:2013-04-08 18:19:13 【问题描述】:

我需要更新一个非唯一字段。我有一张桌子:

create table tbl (A number(5));

tbl 中的值:1、2、2、2 .. 2。

我需要用新的非唯一值替换所有 2 个

新值:1、100、101、102、103 .. 我写道:

DECLARE
    sql_stmt VARCHAR2(500);
   cursor curs is 
        select A from tbl group by A having count(*)>1;
   l_row curs%ROWTYPE;
   i number(5);
   new_mail VARCHAR2(20);
BEGIN
  i:=100;
  open curs;
  loop
    fetch curs into l_row;
    exit when curs%notfound; 
    SQL_STMT := 'update tbl set a='||i||' where a='||l_row.A;
    i:=i+1;
    EXECUTE IMMEDIATE sql_stmt;
  end loop;
  close curs;
END;
/

但我得到了:

         A
----------
         1
       100
       ...
       100

有什么问题吗?为什么循环不起作用?

【问题讨论】:

不清楚您的代码应该做什么。你能在之前和之后添加表格的内容吗? (a) 您期望输出什么? (b) 您是否遇到无法在 Oracle 的 MVCC 下看到自己的更新的问题? Jonathan Leffler,a) 我想用新值替换非唯一字段:1, 100,101,102... b) i++ 确实有效,tbl 已更新,但不正确 但是您的光标按A 分组,因此您将为每个唯一值获取一行,并将该值的所有实例更新为@ 的 same 值987654325@。自行运行该选择以查看它返回的内容。 Alex Poole,我知道,但它现在对我来说并不重要。 【参考方案1】:

怎么样

update tbl
set a = 100 + rownum 
where a in (
    select a 
    from    tbl 
    group by a
    having count(*) > 1 )

子查询找到重复的 A 字段,更新为它们提供从 100 开始的唯一标识符。(您在这里遇到其他问题,例如,如果 id 100、101.... 已经存在怎么办)。

PLSQL 的第一条规则是你可以用 SQL 做的事情总是用 SQL 做。直接写forloop 导致在 sql 和 pl/sql 引擎之间分配上下文切换。即使 oracle 自动将其转换为批量语句 (10g

【讨论】:

同意,如果可能的话,应该在 SQL 中完成,我的意思是在我的回答中这么说。你错过了 group by 子句 *8-) 谢谢!优秀的解决方案【参考方案2】:

每个唯一值 A,您的光标将获得一行:

select A from tbl group by A having count(*)>1;

您需要获取与这些值匹配的所有不同行。一种方法是这样做:

select a, r from (
    select a, rowid as r, count(*) over (partition by a) as c
    from tbl
) where c > 1;

... 然后使用rowid 值进行更新。我不确定您为什么要使用动态 SQL,因为它根本没有必要,您可以简化(IMO)循环:

declare
    i number(5);
begin
    i:=100;
    for l_row in (
        select a, r from (
            select a, rowid as r, count(*) over (partition by a) as c
            from tbl
        ) where c > 1) loop
        update tbl set a=i where rowid = l_row.r;
        i:=i+1;
    end loop;
end;
/

我将其保留为 PL/SQL 以显示您尝试的操作有什么问题,但@haki 非常正确,您应该(并且可以)do this in plain SQL if at all possible。即使您需要它是 PL/SQL,因为您正在循环中执行其他工作(正如 new_mail 字段可能建议的那样),那么您仍然可以在过程中进行一次更新,而不是每次更新一次循环迭代。

【讨论】:

以上是关于Oracle:更新非唯一字段的主要内容,如果未能解决你的问题,请参考以下文章

oracle批量更新的问题

如何更新Django 的ManyToMany 字段

oracle 更新一个列 原来的字段为 ‘你好么’ 更新成 ‘你好’ 为啥 会变成‘你好 ’即多了两个空格。

oracle 把一个字段的值更新另一个字段。

oracle怎么用一个表的多个字段数据更新另一个表相应的字段中

Oracle 批量更新表字段