Oracleでの内部結合を使用したステートメントの更新


298

MySQLで正常に動作するクエリがありますが、Oracleで実行すると次のエラーが発生します。

SQLエラー:ORA-00933:SQLコマンドが正しく終了していません00933
00000-「SQLコマンドが正しく終了していません」

クエリは次のとおりです。

UPDATE table1
INNER JOIN table2 ON table1.value = table2.DESC
SET table1.value = table2.CODE
WHERE table1.UPDATETYPE='blah';

Oracleでtable2を設定して自分の答えをテストしようとしたところ、Oracleが列名としてDESCを拒否したことがわかりました。
Janek Bogucki

申し訳ありませんが、元の列名を省略して、dbでは明らかにそれを明らかにしませんでした
user169743

回答:


412

その構文はOracleでは無効です。あなたはこれを行うことができます:

UPDATE table1 SET table1.value = (SELECT table2.CODE
                                  FROM table2 
                                  WHERE table1.value = table2.DESC)
WHERE table1.UPDATETYPE='blah'
AND EXISTS (SELECT table2.CODE
            FROM table2 
            WHERE table1.value = table2.DESC);

またはこれを行うことができるかもしれません

UPDATE 
(SELECT table1.value as OLD, table2.CODE as NEW
 FROM table1
 INNER JOIN table2
 ON table1.value = table2.DESC
 WHERE table1.UPDATETYPE='blah'
) t
SET t.OLD = t.NEW

インラインビューがOracleによって更新可能と見なされるかどうかによって異なります(2番目のステートメントで更新可能かどうかは、ここにリストされているいくつかのルールによって異なり ます)。


5
私は2番目の例を実行しましたが、selectの列名にエイリアスを追加し、SETでそれらの名前で参照する必要がありましたが、うまくいきました
Gustavo Rubio

41
2番目の例には、実際に更新を実行する前にSQLをテストできるという利点があります。
Daniel Reis

10
2番目の例がうまくいきました。見た目がきれいで読みやすいので、私はそれが好きです。パフォーマンスに関しては、両者の長所と短所がわからない。しかし、私は今のところそのことを心配していませんでした 'cuzこれを使用して、1回限りのスクリプトで不良データを修正しました。
nemo

5
第二は私のために働いた:)。オラクルは強いが奇妙な動物の1つ:/
エラド

10
:更新可能な結合のためのキー保存要件について説明asktom.oracle.com/pls/asktom/...を
ヴァジム・

202

これを使って:

MERGE
INTO    table1 trg
USING   (
        SELECT  t1.rowid AS rid, t2.code
        FROM    table1 t1
        JOIN    table2 t2
        ON      table1.value = table2.DESC
        WHERE   table1.UPDATETYPE='blah'
        ) src
ON      (trg.rowid = src.rid)
WHEN MATCHED THEN UPDATE
    SET trg.value = code;

2
申し分なく動作しますが、Oracleは私に言うmerge into table 1 tように求めました。
Michael-O

1
パーティーに遅れるが、これはまだ良いスレッドです。私は知っておく必要があります、そう...私は何かを逃したのですか?マスターテーブル、「table1」。USINGでは、table1はt1としてエイリアスされています。Table2、別名t2、ただしONでは、参照は... 外部テーブル1-t1ではなく-これは外部テーブルまたはタイプへの参照ですか?Table2?t2ではありませんか?Je suisは混乱しています。より良いエイリアスのファン...
Marc

ここでポイントを1つ挙げると、キー(trg.rowidまたはsrc.rid)に重複する項目が1つある場合、この句はエラーをスローします。ora
Henrique

@MarcではONtrgはマスターテーブルtable1(ロジックによる「外部」テーブル)のエイリアスでありsrcUSINGグループ(ロジックによる「内部テーブル」)を参照します。しかし、ええ、おそらくよりよく参照されたかもしれませんが、私はそれを追跡することができました。
vapcguy

1
@supernova:トニーの答えは、インラインビューを更新することです。これは場合によっては機能しますが、ビューは「キー保持」する必要があります(結合されたすべてのテーブルは、主キーまたはその他の一意のフィールドセットで等価結合する必要があります)。これにより、ターゲットテーブルのすべてのレコードが結果の行セットの最大で1つのレコードに寄与するようになり、したがって、ターゲットテーブルのすべてのレコードが最大で1回更新されます。
Quassnoi

25

MERGEWHERE条項:

MERGE into table1
USING table2
ON (table1.id = table2.id)
WHEN MATCHED THEN UPDATE SET table1.startdate = table2.start_date
WHERE table1.startdate > table2.start_date;

WHERE句で参照されている列はON更新できないため、句が必要です。


このバージョンは間違いなくよりクリーンですが、この構文を使用して変更されていない行の更新トリガーをトリガーするのを回避する方法がないため、トリガーフレンドリーではありません。(トリガーは変更された行に必要であると想定しています。)
sf_jeff


11

上記の回答の一部を使用しないでください。

入れ子になったSELECTの使用を提案する人もいますが、そうするのは大変です。更新するレコードが多い場合は、joinを使用して、次のようにします。

update (select bonus 
        from employee_bonus b 
        inner join employees e on b.employee_id = e.employee_id 
        where e.bonus_eligible = 'N') t
set t.bonus = 0;

詳細については、このリンクを参照してください。 http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx

また、結合するすべてのテーブルに主キーがあることを確認してください。


7

ここに示すよう、Tony Andrewsによって提案された最初のソリューションの一般的な構文は次のとおりです。

update some_table s
set   (s.col1, s.col2) = (select x.col1, x.col2
                          from   other_table x
                          where  x.key_value = s.key_value
                         )
where exists             (select 1
                          from   other_table x
                          where  x.key_value = s.key_value
                         )

これは、複数のフィールドを更新する場合は特に興味深いと思います。


これは私にはうまくいきません。テーブル全体を更新します。
Natassia Tavares 2017

3

次の構文は私にとってはうまくいきます。

UPDATE
(SELECT A.utl_id,
    b.utl1_id
    FROM trb_pi_joint A
    JOIN trb_tpr B
    ON A.tp_id=B.tp_id Where A.pij_type=2 and a.utl_id is null
)
SET utl_id=utl1_id;

@JimGarrisonダウン投票を削除できるように、この回答を再編集してください...この構文を使用しようとしていて、テーブルを更新していませんでした。私が理由を見つけました-私SETが実行していて、REPLACE列の特定の文字列を空白にしようとしていた''-Oracleはnullとして扱われ、このフィールドはnullにできないことがわかりました。構文は実際の一時テーブルではなく一時テーブルを更新しているだけだと思っていましたが、間違っていました。
vapcguy

2

table2にdescの代わりにdescriptionを使用すると、

update
  table1
set
  value = (select code from table2 where description = table1.value)
where
  exists (select 1 from table2 where description = table1.value)
  and
  table1.updatetype = 'blah'
;

table2で2つの個別のクエリを実行する理由
Jitendra Vispute

2

それは正常に動作します

merge into table1 t1
using (select * from table2) t2
on (t1.empid = t2.empid)
when matched then update set t1.salary = t2.salary

その最後にカンマを追加することで、複数のプロパティを設定できます。t1.First_Name = t2.FirstName, t1.Last_Name = t2.LastName"UserName"列(t1.UserName = t2.UserName)でテーブルを照合してから、UserInfo(select * from UserInfo) t2)というテーブルから名前を取得する必要がありました。データベースは、FirstNameとLastNameをテーブルに直接配置するのではなく、UserInfoの主キーとしてUserNameをどこでも使用するようなデータベースでした。これで解決しました!
vapcguy

この答えは、あなたの5年前にQuassnoiによって既に提供された答えに何も追加しません。
飼料:

0
UPDATE table1 t1
SET t1.value = 
    (select t2.CODE from table2 t2 
     where t1.value = t2.DESC) 
WHERE t1.UPDATETYPE='blah';

0
UPDATE IP_ADMISSION_REQUEST ip1
SET IP1.WRIST_BAND_PRINT_STATUS=0
WHERE IP1.IP_ADM_REQ_ID        =
  (SELECT IP.IP_ADM_REQ_ID
  FROM IP_ADMISSION_REQUEST ip
  INNER JOIN VISIT v
  ON ip.ip_visit_id=v.visit_id
  AND v.pat_id     =3702
  ); `enter code here`

0

完全性の問題と同じように、そして私たちがOracleを話しているので、これもそれを行うことができます:

declare
begin
  for sel in (
    select table2.code, table2.desc
    from table1
    join table2 on table1.value = table2.desc
    where table1.updatetype = 'blah'
  ) loop
    update table1 
    set table1.value = sel.code
    where table1.updatetype = 'blah' and table1.value = sel.desc;    
  end loop;
end;
/

1
これはそれを行うことができますが、それは可能な限り遅い方法についてです。
APC

-1
UPDATE (SELECT T.FIELD A, S.FIELD B
FROM TABLE_T T INNER JOIN TABLE_S S
ON T.ID = S.ID)
SET B = A;

AとBはエイリアスフィールドであり、テーブルをポイントする必要はありません。


1
こんにちは、ダン。あなたはすでに非常に良い答えを持っているかなり古い質問に投稿しています。質問が他のソリューションよりも望ましい場合を説明できますか?
Noel Widmer

1
もちろん、私はb = aがテーブル名(table1.B = table2.A)をポイントすることによって記述された回答を見ましたが、テーブルをポイントする必要はありません。
ダンアンダーソン

実際には、テーブルにマップされるビューからフィールドを更新しています。内部ビューのエイリアスがhの場合、「自己文書化」バージョンは「set hb = ha」になります。
sf_jeff

-4
update table1  a 
   set a.col1='Y' 
 where exists(select 1 
                from table2 b
               where a.col1=b.col1 
                 and a.col2=b.col2
             )
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.