Sql 我的update语句与Oracle中的join有什么问题?

Sql 我的update语句与Oracle中的join有什么问题?,sql,oracle,sql-update,Sql,Oracle,Sql Update,我正在使用一个Oracle10g数据库 我有以下两个表格: T_DEBTOR : - ID_DEBTOR - HEADER T_ELEMENT : - ID_ELEMENT - ID_DEBTOR - INSURER 这两个表使用ID_字段连接 仅当标题不为null时,我想用关联的T_DEBTOR.HEADER更新T_ELEMENT.insurance值。 换句话说: If T_DEBTOR.HEADER != null Then T_ELEME

我正在使用一个Oracle10g数据库

我有以下两个表格:

T_DEBTOR :
    - ID_DEBTOR
    - HEADER
T_ELEMENT :
    - ID_ELEMENT
    - ID_DEBTOR
    - INSURER
这两个表使用ID_字段连接

仅当标题不为null时,我想用关联的T_DEBTOR.HEADER更新T_ELEMENT.insurance值。 换句话说:

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);
此查询适用于链接到标头不为null的债务人的所有元素。 但是,当T_DEBTOR.HEADER为null时,此查询将T_元素.insurator设置为null,这是不正确的

即:

我的问题出了什么问题

编辑,关于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;
你试过了吗

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;
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);

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

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

你试过了吗

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;
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);
或者类似的东西 诚然,这有点没有选择性,但我认为它会达到您的目的。

自从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;
干杯,

--

Vincent

您可以使用SQL Case语句来区分标头何时为空以及何时有值:
好问题

为了模拟您的情况,我创建了示例表:

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.
对于您当前的update语句,问题变得很清楚:“not to update”值设置为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.
问候,,
Rob.

您可以通过更新select的结果来实现这一点,但表必须“保留键”:

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

@罗布:谢谢你的提示。我有几个箱子需要用这个。我希望我的DBA能够做到这一点。有几次我不得不创建一个光标来绕过这个问题

那不是我要找的。在我的程序中,elt.ID_债务人从不为空。我想要的:如果关联的债务人(即elt.ID_Debtor=Debtor.ID_Debtor)的标题为null,我不想更新elt。我已经尝试了您的解决方案,并且成功了!它并不比我的建议快,但是它确实比阅读要好得多!但是,由于这会更新表中的每一行,因此它可能会比其他选项生成更多的重做。如果您在此表上有审核、历史记录跟踪或触发器,则可能会给自己造成问题。您的解决方案也在运行。我在搜索过程中看到过这种语法,但要准确地获取它有些困难。。。谢谢。最后,您使用了与Vincent提供的解决方案相同的解决方案,但是您的解释非常完整!谢谢顺便说一下,T_DEBTOR.ID_DEBTOR确实是一个主键。他可能没有,因为这是一个未记录的提示,因此不受支持。有些版本的10g无法正常工作。在生产代码中我不会碰它。