6

Oracle10gデータベースを使用しています。

次の2つのテーブルがあります。

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

これらの2つのテーブルは、ID_DEBTORフィールドを使用して結合されます。

HEADERがnullでない場合にのみ、関連する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);

このクエリは、ヘッダーがnullではない債務者にリンクされているすべての要素に対して機能します。ただし、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

私のクエリの何が問題になっていますか?

ブライアン・ストラーの答えに関して、編集してください:

私がやりたいのはそのようなものです:

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

8 に答える 8

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.

よろしく、ロブ。

于 2009-06-10T13:39:27.373 に答える
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);

より良い解決策がある場合は、遠慮なく投稿してください!

于 2009-06-10T13:25:10.820 に答える
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;

乾杯、

-
ヴィンセント

于 2009-06-10T13:28:26.633 に答える
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);

または同様のことは確かにこれは少し非選択的ですが、私はそれがあなたの意図したことをするだろうと思います。

于 2009-06-10T13:26:47.463 に答える
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
于 2009-06-10T13:42:19.177 に答える
0

@Rob /*+bypass_ujvcをありがとう*/ヒント。これを使用する必要がある場合がいくつかあります。私のDBAがこれができるように言われたらいいのにと思います。これを回避するためにカーソルを作成しなければならなかったことが2、3回あります。

于 2011-03-24T19:36:10.897 に答える
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;
于 2009-06-10T12:45:05.767 に答える
0

SQL Caseステートメントを使用して、HEADERがnullの場合と値がある場合を区別できます:
http ://www.tizag.com/sqlTutorial/sqlcase.php

于 2009-06-10T13:29:25.490 に答える