在 Oracle 中从同一表、不同行进行多列更新,列不为空:接收错误 01407

Lea*_*nne 3 oracle sql-update

我收到一个我不明白的错误。

我有一个 Oracle 数据库(我认为是 11g),其中的表具有多列唯一标识符。它是一个事务表,从不同的表中获取数据的前后快照。到目前为止一切顺利,一切顺利。

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

我在多列更新方面找到了各种很大的帮助,我认为我有它,除了......它会生成一个错误,它无法将非空列更新为空,当我没有办法时可以看到一个 null 进入那里。显然,我做错了什么;我只是不知道是什么。

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

该表中有以下数据,例如:

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 
Run Code Online (Sandbox Code Playgroud)

所以我需要将第二行(无数量,trans_type 9)更新为actual_cost 20;数量可以保留为空。我需要将第 4 行更新为数量 3,实际成本为 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
)
Run Code Online (Sandbox Code Playgroud)

当我运行这个时,我得到:

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

(我尝试了另一种方式 - 更新(选择 col1、col2 等) - 并且表格没有正确设置。太糟糕了,因为这种方式看起来更容易理解......)

我可能也需要有一个外在吗?其他帖子并没有表明我这样做了,而且我也不知道如何表述。

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

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
)
Run Code Online (Sandbox Code Playgroud)

2 的 object_type 没有空数量,无论如何我不会尝试这个数量......

我运行来检查实际的 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
Run Code Online (Sandbox Code Playgroud)

正如我所期望的,这得到了正确的值、正确的旧/新字段,只返回了 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
)
Run Code Online (Sandbox Code Playgroud)

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

我知道桌子的设置,可以说,远非理想。今晚解决不了。

Bob*_*ica 5

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

第一次更新的唯一真正问题是子句中对表WHERE进行子集化的行NEW应该从子查询中取出并放入WHERE语句的子句中UPDATE,如下所示:

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;
Run Code Online (Sandbox Code Playgroud)

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

SQLFiddle 在这里

分享并享受。