我在 Oracle 中加入的更新语句有什么问题?
我正在使用 Oracle 10g 数据库.
I am working with an Oracle 10g Database.
我有以下两张表:
T_DEBTOR :
- ID_DEBTOR
- HEADER
T_ELEMENT :
- ID_ELEMENT
- ID_DEBTOR
- INSURER
这两个表使用 ID_DEBTOR 字段连接.
These two tables are joined using the ID_DEBTOR field.
只有当 HEADER 不为空时,我才想用关联的 T_DEBTOR.HEADER 更新 T_ELEMENT.INSURER 值.换句话说:
I want to update the T_ELEMENT.INSURER value with the associated T_DEBTOR.HEADER only if HEADER is not null. In others words:
If T_DEBTOR.HEADER != null
Then T_ELEMENT.INSURER = T_DEBTOR.HEADER
Else T_ELEMENT.INSURER is not modified!
我尝试使用以下 SQL 查询:
I tried to use the following SQL query:
update
T_ELEMENT elt
set elt.INSURER = (
select HEADER
from T_DEBTOR debtor
where
debtor.HEADER is not null
and debtor.ID_DEBTOR = elt.ID_DEBTOR);
此查询适用于与 HEADER 不为空的债务人相关联的所有元素.但是,当 T_DEBTOR.HEADER 为 null 时,此查询将 T_ELEMENT.INSURER 设置为 null,这是不正确的.
This query is working for all elements linked to debtors that has a HEADER not null. However, when the T_DEBTOR.HEADER is null, then this query set the T_ELEMENT.INSURER to null, which is not correct.
即:
If T_DEBTOR.HEADER != null
Then T_ELEMENT.INSURER = T_DEBTOR.HEADER --> This part is OK
Else T_ELEMENT.INSURER is set to null --> This part is NOT OK
我的查询有什么问题?
编辑,关于 Brian Storrar 的回答:
我想做的是这样的:
update
T_ELEMENT elt
set elt.INSURER = (
select HEADER
from T_DEBTOR debtor
where
debtor.HEADER is not null
and debtor.ID_DEBTOR = elt.ID_DEBTOR)
where debtor.HEADER is not null;
推荐答案
好问题.
为了模拟您的情况,我创建了示例表:
To simulate your situation, I've created sample tables:
SQL> create table t_debtor(id_debtor,header)
2 as
3 select 1, 'Header 1' from dual union all
4 select 2, null from dual union all
5 select 3, 'Header 3' from dual
6 /
Tabel is aangemaakt.
SQL> create table t_element (id_element,id_debtor,insurer)
2 as
3 select 1, 1, 'to be updated' from dual union all
4 select 2, 1, 'to be updated' from dual union all
5 select 3, 2, 'not to be updated' from dual union all
6 select 4, 2, 'not to be updated' from dual union all
7 select 5, 3, 'to be updated' from dual
8 /
Tabel is aangemaakt.
使用您当前的更新语句,问题变得清晰:不更新"值设置为 NULL:
And with your current update statement, the problem becomes clear: the "not to be updated" values are set to NULL:
SQL> update
2 T_ELEMENT elt
3 set elt.INSURER = (
4 select HEADER
5 from T_DEBTOR debtor
6 where
7 debtor.HEADER is not null
8 and debtor.ID_DEBTOR = elt.ID_DEBTOR)
9 /
5 rijen zijn bijgewerkt.
SQL> select * from t_element
2 /
ID_ELEMENT ID_DEBTOR INSURER
---------- ---------- -----------------
1 1 Header 1
2 1 Header 1
3 2
4 2
5 3 Header 3
5 rijen zijn geselecteerd.
进行此更新的最佳方法是更新两个表的连接.但是有一些限制:
The best way to do this update, is to update a join of both tables. There are some restrictions however:
SQL> rollback
2 /
Rollback is voltooid.
SQL> update ( select elt.insurer
2 , dtr.header
3 from t_element elt
4 , t_debtor dtr
5 where elt.id_debtor = dtr.id_debtor
6 and dtr.header is not null
7 )
8 set insurer = header
9 /
set insurer = header
*
FOUT in regel 8:
.ORA-01779: cannot modify a column which maps to a non key-preserved table
通过绕过 ujvc 提示,我们可以绕过这个限制.但除非您确实确定 t_debtor.id_debtor 是独一无二的,否则不建议这样做.
With the bypass ujvc hint, we can circumvent this restriction. But it is not advisable to do so unless you know really really sure that t_debtor.id_debtor is unique.
SQL> update /*+ bypass_ujvc */
2 ( select elt.insurer
3 , dtr.header
4 from t_element elt
5 , t_debtor dtr
6 where elt.id_debtor = dtr.id_debtor
7 and dtr.header is not null
8 )
9 set insurer = header
10 /
3 rijen zijn bijgewerkt.
SQL> select * from t_element
2 /
ID_ELEMENT ID_DEBTOR INSURER
---------- ---------- -----------------
1 1 Header 1
2 1 Header 1
3 2 not to be updated
4 2 not to be updated
5 3 Header 3
5 rijen zijn geselecteerd.
最好只添加一个主键.你可能已经有了这个:
It's better to just add a primary key. You'll probably have this one already in place:
SQL> rollback
2 /
Rollback is voltooid.
SQL> alter table t_debtor add primary key (id_debtor)
2 /
Tabel is gewijzigd.
SQL> update ( select elt.insurer
2 , dtr.header
3 from t_element elt
4 , t_debtor dtr
5 where elt.id_debtor = dtr.id_debtor
6 and dtr.header is not null
7 )
8 set insurer = header
9 /
3 rijen zijn bijgewerkt.
SQL> select * from t_element
2 /
ID_ELEMENT ID_DEBTOR INSURER
---------- ---------- -----------------
1 1 Header 1
2 1 Header 1
3 2 not to be updated
4 2 not to be updated
5 3 Header 3
5 rijen zijn geselecteerd.
问候,抢.
相关文章