• ベストアンサー

updateの一括実行

SQLに関しまして質問させて頂きます。 更新元テーブルA、マスタテーブルB、更新先テーブルCがあり、 以下のような条件を一つのSQL文で実現したいと思っています。 【条件】 (1)Aのe列が1のものを対象に更新をかける (2)条件(1)を満たすレコードの各所属&氏名をマスタBのIDに置き換え、テーブルCに更新 【テーブルA(更新元)】 ----------------------------------------------- No 所属1 氏名1 所属2 氏名2 所属3 氏名3 e 01 A01  ああ  A01  いい  C01  おお 1 02 A01  いい  A01  うう  C01  おお 0 03 B01  ああ  B01  ええ  C01  おお 1 ----------------------------------------------- 【テーブルB(マスタ)】 ----------------- ID  所属 氏名 001  A01  ああ 002  A01  いい 003  B01  ああ : ----------------- 【テーブルC(更新先)】 ------------------ No ID1 ID2 ID3 01 001 002 025 02 002 003 025 03 011 014 025 ------------------ テーブルAが1レコードであれば update C set ID1=(select ID from A, B where A.所属1=B.所属 AND A.氏名1=B.氏名) ID2=(select ID from A, B where A.所属2=B.所属 AND A.氏名2=B.氏名) ID3=(select ID from A, B where A.所属3=B.所属 AND A.氏名3=B.氏名) where No='01' で行くのですが、10000行の更新で10000回update文を発行すると処理に時間がかかります。 そこで、updateの一括実行を行いたいと考えています。 ご存知の方がいらしましたら、 ご教授よろしくお願い致しますm(_ _)m 【環境】 oracle 9i

  • Oracle
  • 回答数3
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

何を悩んでいるのか理解するのに時間がかかりました..(^^ あなたが書かれたUPDATE文で使っているサブクエリは、 更新対象のCとAやBの条件を書いていないので、 予め対象を限定しないと誤動作するのです。 原則として、UPDATEで使うサブクエリは、相関サブクエリに なるように、更新対象テーブルとの関係をサブクエリの条件に 加える必要があると認識してください。 例えば、こんな感じ。 update C set ID1=(select ID from A, B where C.No=A.No AND A.e=1 AND A.所属1=B.所属 AND A.氏名1=B.氏名), ID2=(select ID from A, B where C.No=A.No AND A.e=1 AND A.所属2=B.所属 AND A.氏名2=B.氏名), ID3=(select ID from A, B where C.No=A.No AND A.e=1 AND A.所属3=B.所属 AND A.氏名3=B.氏名), where exists(select 1 from A where A.e=1 and A.No=C.No) ;

zuchisu
質問者

お礼

回答ありがとうございます。この方法で100件の更新が成功したので10000件の更新ができるよう頑張ります。 初め上記方法に似たSQLでやっていたのですが、サブクエリの方で複数行返ってきてしまい実行できませんでした。その理由が「原則として・・・」ですべてが理解できました。 この度は本当にありがとうございます。今後ともよろしくお願いします。

その他の回答 (2)

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

>所属と氏名が入っていない場合(所属B,氏名Bがなしの場合。どちらかが無いのは無い)もあるのですが、selectでマスタ値のみとってくるとそのあたりはどうなりますか?nullでしょうか?それともその列が返ってこない? #1で書いたSQLでは返ってきません。 理由は、Aテーブルと各Bテーブルの結合が内部結合だからです。 外部結合にすれば、IDはnullで返されます。

zuchisu
質問者

補足

上記どおり、外部結合にして試してみましたが、30分ほど待ってみても結果が返ってきませんでした。。。 件数が多すぎるのが問題でしょうか。。。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

update C set(ID1, ID2, ID3) = ( select B1.ID, B2.ID, B3.ID form A, B B1, B B2, B B3 where A.所属1=B1.所属 AND A.氏名1=B1.氏名 and A.所属2=B2.所属 AND A.氏名2=B2.氏名 and A.所属3=B3.所属 AND A.氏名3=B3.氏名 and A.e = 1 and A.No = C.No) こんな感じかな? setの書き方はOracleの方言ですので他のDBでは使えません。 #テーブルAがIDじゃなく所属と名前を持っている構成がよくわかりませんが・・・

zuchisu
質問者

補足

早速のご回答ありがとうございます。 所属と氏名が入っていない場合(所属B,氏名Bがなしの場合。どちらかが無いのは無い)もあるのですが、selectでマスタ値のみとってくるとそのあたりはどうなりますか?nullでしょうか?それともその列が返ってこない? 情報が不十分ですみません。 #テーブルAがIDじゃなく所属と名前を持っている構成がよくわかりませんが・・・ ファイルをそのままワーク表として読み込んだので、こうなりました。。。

関連するQ&A

  • SELECTを含むUPDATEについて

    2つののテーブルがあり、テーブル1のデータを元にテーブル2を更新させたい場合、SELECT文を含むUPDATE文で更新出来ると思うのですが、どのようにしたら一番効率的でしょうか? 例)テーブル1~table1 no ken city ---------------------------------- 01 北海道 根室 03 青森 八戸 05 千葉 柏 08 埼玉 さいたま 09 東京 千代田区 例)テーブル2~table2 no ken city ---------------------------------- 01 02 03 04 05 06 07 08 09 テーブルが2つあり、テーブル1の情報を元にテーブル2を更新したい。 条件は、noが一致していること。 A) kenを更新するには、 ↓ UPDATE `table2` SET ken = (SELECT ken from table1 WHERE table1.no = table2.no) B) kenとcityを更新するには、 ↓ UPDATE `table2` SET ken = (SELECT ken from table1 WHERE table1.no = table2.no), city = (SELECT city from table1 WHERE table1.no = table2.no) SELECT以下が同じなのでもうちょっとスマートに短く記述する方法はあるんでしょうか?

    • ベストアンサー
    • MySQL
  • select for updateのロック

    オラクルのselect for updateでロックをするタイミングがいつですか? こんなPL/SQLのコードがあったとします。 ---↓↓↓ソースコードここから↓↓↓------------------------- select * from テーブル1 where id = 1 for update; ・・・・・(a) ~ update テーブル1 set kingaku=100 where id = 1 ・・・・・(b) ~ commit; ---↑↑↑ソースコードここまで↑↑↑------------------------- id = 1のレコードがロックされるのは(a)、(b)どちらのタイミングですか? また、このロックは ・他トランザクションから読めるけど更新できない ・他トランザクションからは読むことすらできない のどちらでしょうか? よろしくお願いします。

  • Oracleのupdate文について

    OracleでテーブルB、Cを結合し取得できた項目で、テーブルAを更新したいのですがSQLがわかりません。結合結果とテーブルAは1:1にはなりません。 件数が結合結果>テーブルAの時もあれば、その逆の場合もあります。また、複数項目を更新したいです。実行して考えてみたいのですが、明朝客先ですぐに実行しなければならず(テスト環境はあるので明日そこで一旦確認後、すぐに本番環境で実行)、現在移動中→ホテル泊のため余裕がありません。 ネットで下記を見つけたのですが、更新する項目に更新日時を追加したいのと、テーブルAとの紐付けやEXISTSのWHEREはテーブルBとC両方の項目に紐づけたいです。 また、テーブルAの更新条件に、テーブルB、Cにはないcolumn③に対する条件も追加したいです。 UPDATE [TABLE①] A SET (COLUMN①, COLUMN②) = ( SELECT B.COLUMN, C.COLUMN FROM [TABLE②] B, [TABLE③] C WHERE B.COLUMN = C.COLUMN AND B.COLUMN = A.COLUMN ) WHERE EXISTS ( SELECT 1 FROM [TABLE②] B2 WHERE B2.COLUMN = A.COLUMN) もろもろとわかりづらい説明&他力本願で心苦しいのですが、どなたか教えていただけないでしょうか?

  • 一つ前のレコードの値と減算して、別テーブルにUPdateする方法について

    テーブル1のデータを計算してテーブル2を作成したいと考えております。 計算については"数値"を更新日付の一つ前の値と引き算してその結果をテーブル2に挿入したいと思ってます。 テーブル1 ID 数値 更新日付 001 23 2008/02/23 2:00:00 001 34 2008/02/23 3:00:00 001 50 2008/02/23 4:00:00 001 23 2008/02/23 5:00:00 002 25 2008/02/23 3:00:00 002 50 2008/02/23 4:00:00 002 70 2008/02/23 5:00:00 002 50 2008/02/23 6:00:00 結果 テーブル2 ID 数値 更新日付 001 11  2008/02/23 3:00:00 001 16  2008/02/23 4:00:00 001 -27 2008/02/23 5:00:00 002 25  2008/02/23 4:00:00 002 20  2008/02/23 5:00:00 002 -20 2008/02/23 6:00:00 一応考えたのですが SELECT * FROM テーブル1 AS a, テーブル1 AS b WHERE (((a.ID)=[b].[ID]) AND ((b.更新日付)=(select min(更新日付) from テーブル1 as b where a.更新日付 < b.更新日付))) ORDER BY a.ID, a.更新日付); として、aとbの数値を引き算しようと考えていますが、可能なのでしょうか? ぜんぜん別の方法でもいいので教えていただけないでしょうか? 以上 よろしくお願いいたします。

  • ACCESSでのUPDATEコマンド

    現在ASPとACCESSを使用して、開発を行っています。 ORACLEでの開発経験はあるのですが、SQLServerやACCESSでの経験がなく微妙にことなるSQLに困惑しています。 ORACLEではUPDATE時に他のテーブルからデータを参照して更新できると思いますがACCESSで同じようなことはできるのでしょうか?実行したいのはORACLEでいう、以下のようなSQLです。 SQLを2回に分けて実行すれば同じことはできるのですが・・・。 UPDATE TAB_A SET (A,B) = (SELECT A1,B1 FROM TAB_B WHERE C1='10') WHERE C = '10'; 宜しくお願いします。

  • 複雑なUPDATE文2

    先に質問をさせていただき、1度は解決したものの再び行き詰ってしまいました。 UPDATEの際うまくいかず困っています。 お知恵を拝借いただけると助かります。 使用バージョンはPostgresV7.3.4です。 tableA a1|a2|b|c -+--+-+- 1 | 1 | 1| 1 (★) 1 | 1 | 0| 1 1 | 2 | 0| 1 2 | 2 | 1| 0 2 | 1 | 0| 1 3 | 2 | 1| 1 (★) 3 | 2 | 0| 1 3 | 1 | 0| 1 b=1 and c=1 で一致する行を★行とする。 ★行のa1列の値とa2列の値(上記の例だと(a1=1,a2=1)と(a1=3,a2=1))をもつ行に対して 下記の条件◆でUPDATEを行う。 [条件◆] b=0 and c=1 [UPDATEの内容] 条件◆に一致したc列を3に更新する [理想の結果] tableA a1|a2|b|c -+--+-+- 1 | 1 | 1| 1 1 | 1 | 0| 3 ←更新 1 | 2 | 0| 1 2 | 2 | 1| 0 2 | 1 | 0| 1 ←★にあてはまらないので更新されない 3 | 2 | 1| 1 3 | 2 | 0| 3 ←更新 3 | 1 | 0| 1 ←最下行 ========================================== UPDATE tableA set c = 3 WHERE 条件◆ and a1 in (select a1 from tableA where b=1 and c=1) and a2 in (select a1 from tableA where b=1 and c=1) このようなイメージなのですが、この場合、 最下行のc列も更新してしまいました。 (説明しずらいのですが、) a1とa2の条件は独立させるのでは無く、セットとして考えたいのですが、 方法が分りません。 ご協力お願いします。 ==========================================

  • distinct をexistsに変換する

    distinctをexistsに変換した方がパフォーマンスが良いようで、 例えば以下の例があるとします ---------------------------------- (前)SELECT DISTINCT a.ID1, a.NAME1 FROM TABLE1 a, TABLE2 b WHERE a.ID1 = b.ID2 (後)SELECT a.ID1, a.NAME1 FROM TABLE1 a    WHERE EXISTS ( SELECT 'X' FROM TABLE2 b WHERE a.ID1 = b.ID2) ---------------------------------- もっと複雑なSQLの場合、EXISTSに変換できるのでしょうか?。複雑なSQLとは、 「複数のテーブルからカラムを取得」「テーブル結合が2つ以上」「外部結合」 などのSQLで、以下に例を示します。 (例)SELECT DISTINCT a.ID1,a.NAME1,b.ID2,b.NAME2,c.ID3,c.NAME3    FROM TABLE1 a,TABLE2 b,TABLE3 c    WHERE a.ID1 = b.ID1(+)      AND a.ID1 = c.ID1(+)

  • UPDATEが動いたり止まったり…

    SQLServer2000SP4の環境で、 夜間バッチ処理で update テーブルA set 項目A1 = (select 項目B1 from テーブルB where 項目B2 = 項目A2) where 項目A2 in( select 項目A2 from テーブルA left outer join テーブルB on 項目A2 = 項目B2 where 項目A1 <> 項目B1 ) という処理で、テーブルAとテーブルBの項目1という値が違うものだけ対象にして、テーブルBの項目1をテーブルAの項目1にセットしています。 この処理で正常に終わることがほとんどなのですが、月に2度程、このコマンドのまま停止した状態(エラーなし。コマンドタイムアウトは0にしています)になることがあります。 きっかけとしては、テーブルAのA1にインデックスを設けたということがあり、エラー対策としてインデックスデフラグを処理直前にかけていました。いっときは正常に動いていたのですが、また停止したので、インデックスフラグメントが原因ではなさそうです。(ちなみにこのUPDATEで更新される件数は数十件です) テーブルA:100万レコード程 主キー:項目A2 インデックス:項目A1 テーブルB:100万レコード程 主キー:項目B2 エラーメッセージも何もでなくて、処理が継続中のような状態で止まっているのでこのUPDATE一文でインデックス更新にロックが掛かっているのかなと勝手に想定はしておりますが、どなたか原因と回避を教えていただきたく質問させて頂きました。よろしくお願いいたします。

  • 副問い合わせを使わずに書く方法

    テーブルAとBがあり、どちらも列idとnameがあります。Aのnameは最初はNULLです。AのnameをBから持ってきてUPDATEしたい(AのidのうちBにあるもののnameをAにコピーする)のですが、MySQLのバージョンが古く、副問い合わせが使えず、以下のようなことができないので困っています。どなたか教えていただけませんか。 UPDATE A SET name = ( SELECT name FROM B WHERE A.id = B.id ) WHERE EXISTS ( SELECT 'X' FROM B WHERE A.id = B.id ) ;

    • ベストアンサー
    • MySQL
  • データが存在しないか条件に一致する場合の条件文

    bテーブルにc=a.cのデータが存在しない、あるいはc=a.cに一致するフィールドdの時刻が10分経過している場合にUPDATEを実行するクエリを考案中です。ベタ書きすると以下のようになると思うのですが、同じSELECT文が2回出てきます。これらをまとめることは可能でしょうか。 UPDATE a SET foo=? WHERE id=? AND (NOT EXISTS(SELECT d FROM b WHERE c = a.c) OR TIMEDIFF((SELECT d FROM b WHERE c = a.c), NOW()) > '00:10:00');

    • ベストアンサー
    • MySQL