我在Oracle中加入的更新语句出了什么问题?

时间:2009-06-10 12:42:01

标签: sql oracle sql-update

我正在使用 Oracle 10g数据库。

我有以下两个表:

T_DEBTOR :
    - ID_DEBTOR
    - HEADER
T_ELEMENT :
    - ID_ELEMENT
    - ID_DEBTOR
    - INSURER

使用ID_DEBTOR字段连接这两个表。

我想仅在HEADER不为空时才使用关联的T_DEBTOR.HEADER更新T_ELEMENT.INSURER值。 换句话说:

If T_DEBTOR.HEADER != null
    Then T_ELEMENT.INSURER = T_DEBTOR.HEADER
    Else T_ELEMENT.INSURER is not modified!

我尝试使用以下SQL查询:

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非空的debtors的所有元素。 但是,当T_DEBTOR.HEADER为null时,此查询将T_ELEMENT.INSURER设置为null,这是不正确的。

即:

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;

8 个答案:

答案 0 :(得分:6)

好问题。

为了模拟你的情况,我创建了样本表:

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:

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.

执行此更新的最佳方法是更新两个表的连接。但是有一些限制:

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是唯一的,否则不建议这样做。

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.

最好只添加一个主键。你可能已经有了这个:

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.

此致 罗布。

答案 1 :(得分:2)

我找到了解决问题的方法(添加了where子句):

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 exists (
        select null
            from T_DEBTOR debtor
            where debtor.HEADER is not null
                and debtor.ID_DEBTOR = elt.ID_DEBTOR);

如果您有更好的解决方案,请不要犹豫发布!

答案 2 :(得分:2)

自从Oracle 8i(我没有尝试使用前面的版本)之后,如果表是“密钥保留”的话,你可以更新连接(例如:如果你正在以父子关系更新子节点) 。在这里,如果id_debtor是T_DEBTOR的主键,您可以:

UPDATE (SELECT e.insurer, d.header
          FROM t_element e, t_debtor d
         WHERE e.id_debtor = d.id_debtor
           AND d.header IS NOT NULL)
   SET insurer = HEADER;

干杯,

-
文森特

答案 3 :(得分:1)

你试过吗

update
    T_ELEMENT elt
    set elt.INSURER = NVL((
        select HEADER
            from T_DEBTOR debtor
            where
                debtor.HEADER is not null
                and debtor.ID_DEBTOR = elt.ID_DEBTOR), elt.INSURER);

或类似的东西 承认这有点没有选择性,但我认为它会做你想要的。

答案 4 :(得分:1)

您可以通过更新选择的结果来执行此操作,但表必须是“密钥保留”:

SQL> create table t_debtor ( id_debtor integer, header varchar2(10));

Table created.

SQL> create table t_element (id_element integer, id_debtor integer, insurer varchar2(10));

Table created.

SQL> insert into t_debtor values (1, 'something');

1 row created.

SQL> insert into t_debtor values (2, 'else');

1 row created.

SQL> insert into t_debtor values (3, null);

1 row created.

SQL>
SQL> insert into t_element values (1, 1, 'foo');

1 row created.

SQL> insert into t_element values (2, 2, null);

1 row created.

SQL> insert into t_element values (3, 3, 'bar');

1 row created.

SQL> commit;

Commit complete.

创建表格(提示 - 如果您可以为您的示例发布SQL,这非常有用。)。

现在您可以更新选择的结果以提供您想要的内容......

SQL> update (select e.id_element, d.header header, e.insurer insurer
        from t_debtor d, t_element e
  2          where d.id_debtor = e.id_debtor  3
  4          and d.header is not null)
  5  set insurer = header;
set insurer = header
    *
ERROR at line 5:
ORA-01779: cannot modify a column which maps to a non key-preserved table

这失败了,因为表没有保留密钥,但是一些约束将解决这个问题:

alter table t_element add constraint t_element_pk primary key (id_element) using index;

alter table t_debtor add constraint t_debtor_pk primary key (id_debtor) using index;

alter table t_element add constraint t_element_debtor_fk foreign key (id_debtor) references t_debtor(id_debtor);

现在更新将起作用,因为表是密钥保留的:

SQL> update (select e.id_element, d.header header, e.insurer insurer
        from t_debtor d, t_element e
        where d.id_debtor = e.id_debtor
        and d.header is not null)
set insurer = header  2    3    4    5  ;

2 rows updated.

SQL> select * from t_element;

ID_ELEMENT  ID_DEBTOR INSURER
---------- ---------- ----------
         1          1 something
         2          2 else
         3          3 bar

答案 5 :(得分:0)

你试过吗

update
    T_ELEMENT elt
    set elt.INSURER = (
        select HEADER
            from T_DEBTOR debtor
            where
                debtor.HEADER is not null
                and debtor.ID_DEBITEUR = elt.ID_DEBITEUR)
where not elt.ID_DEBITEUR is null;

答案 6 :(得分:0)

您可以使用SQL Case语句来区分HEADER何时为空以及何时具有值:
http://www.tizag.com/sqlTutorial/sqlcase.php

答案 7 :(得分:0)

@Rob感谢/ * + bypass_ujvc * /提示。我有几个案例我需要使用它。我希望我的DBA能够说明这一点。有几次我不得不创建一个游标来解决这个问题。