【问题标题】:Multi-column update from SAME table, different rows, in Oracle, with not-null column: Receiving error 01407在 Oracle 中使用非空列从 SAME 表、不同行更新多列:接收错误 01407
【发布时间】:2014-04-17 00:39:09
【问题描述】:

我遇到了一个我不明白的错误。

我有一个 Oracle 数据库(我认为是 11g),其中包含一个具有多列唯一标识符的表。这是一个事务表,对不同表中的数据进行前后快照。到目前为止一切顺利,一切正常。

我们的代码中有一个错误,现在我正在尝试修复数据,因为该错误已修复。该错误导致“后”快照在本应保留“前”的情况下将两列归零。因此,我将更新“之后”快照(由事务类型编号标识)以在这两列中具有相同的值。

我在多列更新方面找到了各种很大的帮助,我认为我有它,除了...它会生成一个错误,它无法更新非空值列为空,当我无法看到一个空值进入时。显然,我做错了什么;我就是说不出来是什么。

在某些情况下,一列可以为空 - 有一个对象类型列定义该记录是否可以具有空值。

表中有这些数据,比如说:

object_name      object_type   trans_type   trans_date   quantity    actual_cost
no-quantity      1             1            04/16/2014   {null}      20.00
no-quantity      1             9            04/16/2014   {null}       0.00
needs quantity   2             1            04/16/2014   3           15.00
needs quantity   2             9            04/16/2014   0            0.00 

所以我需要将第二行(无数量,trans_type 9)更新为 actual_cost 为 20;数量可以保持为空。我需要将第 4 行的数量更新为 3,actual_cost 为 15。

这是我尝试运行但失败的查询 - 创建和插入语句如下:

update  demo_table new 
set     (quantity, actual_cost) = 
        (
        SELECT  quantity, actual_cost
        FROM    demo_table old
        WHERE   old.object_name = new.object_name
            and old.object_type = new.object_type
            and old.trans_date = new.trans_date
            and old.trans_type = 1
            and new.trans_type = 9
)

当我运行它时,我得到:

ORA-01407: 无法将 ("myschema"."DEMO_TABLE"."ACTUAL_COST") 更新为 NULL

(我尝试过另一种方式 - 更新(选择 col1、col2 等) - 表格设置不适合它。太糟糕了,因为这种方式看起来更容易理解......)

我可能还需要一个外部 where 吗?其他帖子没有表明我这样做了,我也不知道我将如何制定它。

我什至在这次尝试中得到了非空错误:

update  demo_table new 
set     (actual_cost) = 
        (
        SELECT  actual_cost
        FROM    demo_table old
        WHERE   old.object_name = new.object_name
            and old.object_type = new.object_type
            and old.trans_date = new.trans_date
            and old.trans_type = 1
            and new.trans_type = 9
            and old.object_type = 2
)

object_type of 2 没有空数量,反正我没有尝试这个数量...

我运行来检查实际 where 子句是否正确的 select 语句如下所示:

SELECT  old.object_name as old_name, old.object_type as old_type, old.trans_type as old_trans, old.trans_date as old_date,
    new.object_name as new_name, new.object_type as new_type, new.trans_type as new_trans, new.trans_date as new_date,
    old.quantity as old_quantity, old.actual_cost as old_cost, new.quantity as new_quantity, new.actual_cost as new_cost
FROM    demo_table old, demo_table new
WHERE    old.object_name = new.object_name
    and old.object_type = new.object_type
    and old.trans_date = new.trans_date
    and old.trans_type = 1
    and new.trans_type = 9

这得到了正确的值,正确的旧/新字段,只返回了 2 行,正如我所料。

这是我的创建和插入语句:

create table demo_table (
    object_name varchar2(30) not null,
    object_type number(3) not null,
    trans_type number(3) not null,
    trans_date timestamp(6) not null,
    quantity number(3),
    actual_cost number(17,2) not null
)

insert into demo_table (object_name, object_type, trans_type, trans_date, quantity, actual_cost)
values (
'no-quantity', 1, 1, '16-APR-14', null, 20
)

insert into demo_table (object_name, object_type, trans_type, trans_date, quantity, actual_cost)
values (
'no-quantity', 1, 9, '16-APR-14', null, 0
)

insert into demo_table (object_name, object_type, trans_type, trans_date, quantity, actual_cost)
values (
'needs quantity', 2, 1, '16-APR-14', 3, 15
)

insert into demo_table (object_name, object_type, trans_type, trans_date, quantity, actual_cost)
values (
'needs quantity', 2, 9, '16-APR-14', 0, 0
)

我希望我的问题很清楚。我确实环顾四周,但我找不到任何看起来非常匹配的东西。同表的东西并没有真正覆盖,不可为空的列也没有真正覆盖。 (或者更确切地说,确实如此,但我看不出所描述的问题如何影响我的处境。)

我知道桌子设置,容我们说,远非理想。无法解决,今晚。

【问题讨论】:

    标签: oracle sql-update


    【解决方案1】:

    首先 - 对问题 +1 - 写得很好,有很多支持信息,请接受一个巨大的 谢谢 提供足够的信息来解决问题,包括表格定义和要填充的语句桌子。

    第一次更新的唯一真正问题是WHERE 子句中的行,它是NEW 表的子集,应该从子查询中拉出并放入UPDATE 语句的WHERE 子句中,如:

    update  demo_table new 
    set     (new.quantity, new.actual_cost) = 
            (
            SELECT  old.quantity, old.actual_cost
            FROM    demo_table old
            WHERE   old.object_name = new.object_name
                and old.object_type = new.object_type
                and old.trans_date = new.trans_date
                and old.trans_type = 1
    )
    where new.trans_type = 9;
    

    我不得不和这个玩了很长一段时间才能弄清楚发生了什么。有趣的问题。

    SQLFiddle here.

    分享和享受。

    【讨论】:

    • 谢谢,太好了。奇迹般有效。我在更复杂的现实生活问题中确实遇到了一个问题:我在写这篇文章时忘记提到只有某些 object_types 会以这种方式更新,所以当我这样做时我又遇到了 NULL 问题。简单的解决方法就是把它放到外面的地方。
    • 我可能还会在 where 中添加其他一些东西 - 我将它们放在内部 where,但我认为它们也都需要在外部 where 中。有一个我没有包含的“所有者”列,并且只会更新特定所有者和特定 trans_date 的数据。我认为一般的答案是“加入”信息应该在内部子句中; 'where' 限制应该在内部和外部子句中,即使它在两个 where 子句中相同。再次感谢。我很高兴你喜欢这篇文章;我花了两个小时才把它写成我认为足够有用的方式!
    猜你喜欢
    • 1970-01-01
    • 2021-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-14
    相关资源
    最近更新 更多