MySQL 複数テーブルのフィールドにUPDATE

このQ&Aのポイント
  • MySQLのJOINを使用して複数のテーブルのフィールドを一括でUPDATEする方法について調べています。
  • PHP内で個別にテーブルを更新する方法も考えられますが、一度のSQLクエリでdel_flagの値を一括で更新する方法があるか知りたいです。
  • 調査した結果、特定のテーブルだけでなく、全てのテーブルの該当するフィールドを更新するには、LEFT JOINを使用したUPDATE文を作成する必要があります。具体的なクエリが欲しいです。
回答を見る
  • ベストアンサー

MySQL 複数テーブルのフィールドにUPDATE

よろしくお願いします。 PHP5、MySQL5、 PEAR DB、Smarty にて開発しております。 標題にもありますように、LEFT JOINを使ってUPDATEできる方法を探しております。 ●Aテーブル(親) id | del_flag ----------------- 1 | 0 2 | 0 3 | 0 4 | 0 ●Bテーブル id | del_flag ----------------- 1 | 0 3 | 0 4 | 0 ●Cテーブル id | del_flag ----------------- 1 | 0 2 | 0 3 | 0 4 | 0 上記のような3つ、またはもしくはそれ以上テーブルがあったとします。 そこで、 Aテーブルの id 2 のdel_flagを1 とアップデートしたときに、 同時に全てのB、Cのテーブルの id 2 のdel_flagも 1 としたく思います。 Bテーブルには、id 2 が存在しないため、結果的にはCテーブルだけが更新されますが、 A、B,Cともに同一のid値 がある場合も考慮して、 アップデートしたいと思います。 そこで、PHP内で、一つ一つのテーブルを地道にアップデートすることは可能だとおもいますが、 一度のSQLでdel_flagの値を1とできる方法はございませんでしょうか? お手数ですが、 具体的なクエリを書いていただけると、大変助かります。 いろいろ調べましたが、なかなか上手くいかず・・・・。 よろしくお願いいいたします。  

  • MySQL
  • 回答数5
  • ありがとう数4

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

  • ベストアンサー
  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.4

>left joinでつなげるよりスマートで効率的なのはわかりましたが、 >速度的にはどうなんでしょうね? left joinによるオーバーヘッドを考慮すれば おそらく個別でやった方が早いでしょう。 蛇足ですが、どうも今回の案件について疑問があります。 AテーブルについてはIDがプライマリになっていると思いますが Bテーブル(やCテーブル)についてはどういう仕様なのでしょう? BテーブルでもIDがプライマリなら、いっそのこと同じテーブルで管理すれば よい案件かもしれません。 通常子テーブルというのはIDでつながっても親IDに対して複数のデータを 持つような場合有効ですが、1対1ならあえて分けている意味があるか微妙です。 また、別解ですが、Bテーブルにdel_flg自体をつけること自体に意味があるのでしょか ? Aテーブルの正規化につかっているならAテーブルのdel_flgで処理すればよいし 場合によってBテーブルを単独で検索するとしてもAテーブルをジョインすれば 簡単にdel_flgレベルのことはできそうな気がしますが?

n-yuuki
質問者

お礼

詳しく有難うございます! なるほど! 少し本質が見えてきました。 AのIDはプライマリです。 B,Cテーブルは、言葉たらすでしたが、 じつは複数の同一IDを格納していまして、1対1ではない現状です。 yambejp様のおっしゃる通りでございます。 やはり、オーバーヘッドを考慮すると、 個別の方が早いのですね。 まだまだジョインすることについて慣れておらず、恐る恐る勉強しております。 また、もし 以下のようにLEFT JOIN したとして、  ---------------------------------------- update A left join B on A.id=B.id left join C on A.id=C.id set A.del_flag=1, B.del_flag=1, C.del_flag=1 where A.id=2 ---------------------------------------- BやCのテーブルに 該当するID(AテーブルのプライマリID)が無いテーブル状況だと、処理はエラーとなりますよね? その場合、今の設計的に大変困ったことになります。 なぜなら、十分にBやCにIDが存在しないことがある設計だからです。 この辺り、また自分でも試して研究しようと思いますが、 よろしれば回答下さいませ。 次に、 >また、別解ですが、Bテーブルにdel_flg自体をつけること自体 >に意味があるのでしょか? についてです。 これは私に知識と経験のないことを証明する、根本的な解決策であると 、とてもありがたいご指摘です。 各BやCテーブルは、Aテーブルと正規化されています。 ですので、ご指摘のように、 今ふと考えると、del_flagのフィールドを各テーブルに設置しなくてもいいのだと気づきました。 ただ、いま作っているものが、上記のような正しいコントロールがされないまま開発してしまっているので、今から取り込むのはかなり厄介なことになりそうです。 でも、このような方法で、各ページで使用するデーターを取り込んでいたらと思うと、本当にバカな作りかたをしていたと後悔しています。

その他の回答 (4)

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.5

>BやCのテーブルに >該当するID(AテーブルのプライマリID)が無いテーブル状況だと、処理はエラーとなりますよね? やってみればわかりますが、エラーは出ません また、もしも複数のSQLを投げるのに抵抗があれば、プロシージャを用意するとか・・・ DROP PROCEDURE IF EXISTS SET_FLG; DELIMITER // CREATE PROCEDURE SET_FLG(IN in_id INT,IN num INT) BEGIN SET AUTOCOMMIT=0; START TRANSACTION; UPDATE `table_a` SET `del_flg`=num WHERE `id`=in_id; UPDATE `table_b` SET `del_flg`=num WHERE `id`=in_id; UPDATE `table_c` SET `del_flg`=num WHERE `id`=in_id; COMMIT; END // DELIMITER ; としておき CALL SET_FLG(2,1);

n-yuuki
質問者

お礼

この度は、いろいろと有難うございました。 プロシージャについても勉強になりました。 とにかく、今回の疑問が解決しましたので、ご報告いたいします。 お世話になりました。 また、よろしくお願いいたします。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.3

>でも、UPDATEしたいテーブルが計8つ程ありまして、 >ずらっと8つ連呼するべきでしょうか? 8個のSQLを投げる方が、8個つないで8箇所修正するより 効率的だと思いますよ

n-yuuki
質問者

お礼

なるほど、わかりました。 8回foreachで連呼します。 left joinでつなげるよりスマートで効率的なのはわかりましたが、 速度的にはどうなんでしょうね?

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.2

提示されたものを単純にかくとこうなります update table_a as a left join table_b as b on a.id=b.id left join table_c as c on a.id=c.id set a.del_flg=1,b.del_flg=1,c.del_flg=1 where a.id=2 でも、これって update table_a set del_flg=1 where id=2; update table_b set del_flg=1 where id=2; update table_c set del_flg=1 where id=2; と書く方がましなような気がしますが?

n-yuuki
質問者

補足

確かに下の方がいいよな気もします・・・。 でも、UPDATEしたいテーブルが計8つ程ありまして、 ずらっと8つ連呼するべきでしょうか?

  • o_chi_chi
  • ベストアンサー率45% (131/287)
回答No.1

希望する回答ではありませんが、トリガー機能を使えばよいのでは。

n-yuuki
質問者

お礼

トリガーについて勉強します! 有難うございました。

関連するQ&A

  • MYSQLを用いた集計について

    MySQLを用いた、クロス集計(?)のデータについてどこを探しても見つからなかったので、投稿します。 DBAとDBB、DBCをLEFT JOINを行って、DBCの複数条件の全てのに適合する、DBBの件数をAのID単位で取得したいと思っています。 <テーブル構成> DB:A ---- id PK B_id FK flag ---- DB:B ---- id PK C_id FK flag ---- DB:B ---- id PK flag ---- そこで色々試行錯誤してみたのですが、良い方法が見つからず、現在は確認を兼ねて、以下の様な形で抽出するリストを構築する所 までは行いました。 --- SELECT *,count(DB_B.id) FROM (DB_A LEFT JOIN DB_B on DB_A.B_id = DB_B.id) JOIN DB_C on DB_B.C_id = DB_C.id WHERE DB_A.flag = 100 AND (DB_C.flag = 1 OR DB_C.flag = 2 OR DB_C.flag = 3) GROUP BY DB_B.id HAVING count(DB_C.id) = 3 --- ここで抽出されるリストをDB_Aのid別に件数を取得するにはどうすればよろしいでしょうか? もちろん、上のコードでは無理だろうと予測はついているのですが、ここから先に進めず…。 ちなみに、環境は以下のとおりです。 MySQL:4.0.27 PHP:4.4.4 ※ちなみに、同じような形式でDB_Dの複合条件、DB_Eの複合条件を掛け合わせていく形もあり得るため、それに準じた方法・知恵をご教授いただけると幸いです。 よろしくお願致します。

  • テーブルごとのカウント

    PHP5.2+mysql 5.0.45で開発を行っております。 SQLに関する質問なのですが 以下のことが可能かどうかご教授いただきたく。 4つのテーブルがあります。 (例は適当です。項目の名称等は無視してください。) テーブルA ID Name Kana テーブルB ID NameID Pref City テーブルC ID NameID Tel Fax テーブルD ID NameID email CellPhone とします。 A.ID=1000の時各テーブルのレコード数が A:B:C:D=1:3:2:2となっています。 SQLの出力結果として A.ID A.Name A.Kana B.Count(ID) C.Count(ID) D.Count(ID) という、6項目を出力したいのですが 方法がわかりません。 試してみたのは select A.ID,A.Name,A.Kana,Count(B.ID),Count(C.ID),Count(D.ID) from A left join B on A.ID = B.NameID left join C on A.ID = C.NameID left join D on A.ID = D.NameID where A.ID = 1000 group by A.ID,A.Name,A.Kana ですが 結果、 A.ID = 1000 A.Name = Name A.Kana = Kana Count(B.ID) = 3 Count(C.ID) = 3 Count(D.ID) = 3 となってしまいます。 冷静に考えるとそうなんですが・・・ もしうまく結果を取得できる方法があればご教授いただきたく よろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • テーブル結合で、結合フィールドをWHERE句に用いた時に、結合フィールドのデータがNULLになってしまう。

    MySQL 4.0.24-standard + PHP Version 4.3.11 を使用しています。 下記のような table_a, table_b があり、idフィールドで外部結合させています。 table_a id|value ------- 1 | 0 2 | 1 table_b id|name ------- 1 | A 2 | B SELECT * FROM table_a NATURAL LEFT OUTER JOIN table_b; result id|value|name -------------- 1 | 0 | A 2 | 1 | B しかし、下記のクエリでは、このようにidがNULLになってしまいます。 SELECT * FROM table_a NATURAL LEFT OUTER JOIN table_b WHERE table_a.id = 1; result id |value|name -------------- NULL| 0 | A 以下のような結果を得たいのですが、どうすれば良いのでしょうか? result id|value|name -------------- 1 | 0 | A

    • ベストアンサー
    • MySQL
  • MySQL複数テーブルからの情報取得に関しまして

    Aテーブル...ユーザ情報 Bテーブル...商品情報(AテーブルのユーザIDを列として持っています) Cテーブル...アイテム情報(Bテーブルの商品IDを列として持っています) Bテーブルの一覧リスト表示の画面にて、検索項目として、 Aテーブルのユーザ名、Cテーブルのアイテム名があります。 現在は、LEFT JOINを使って、検索、呼び出しを行っておりますが、 多数のカラムを指定して呼び出しを行っているため、SQL文が長くなってしまっており、 もっとすっきりとしたSQL文を記述したいと考えております。 ※Aテーブル,Bテーブルの組み合わせは他の画面でもよく使われております。 viewという機能を使うことによって、これをすっきりと記述できるようになるのではないかと考えておりますが、viewはこのような使い方をしてもいいのでしょうか。 または、もっとすっきりとした記述を行う技術のアドバイスをお願いいたします。 よろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • 2つのテーブルのupdate

    AtableというテーブルとBtableというテーブルのTypeフィールドをupdateする場合、テーブルが異なるごとにmysql_queryを使っているのですが、この場合、ひとつにまとめられないものでしょうか? このような使用方法が通常ですか? よろしくお願い致します。 $ASQL = "update Atable set Type = 1 where id = $a"; $BSQL = "update Btable set Type = 1 where id = $b"; mysql_query($ASQL); mysql_query($BSQL);

  • 複数テーブルの結合の仕方

    いつもお世話になっております。 MySQLとPHPで開発をしております。 複数のテーブルからのデータの取得方法について教えていただきたいです。 テーブル:qes(key:q_id) |q_id|memo|del_id| +------------------+ |1 |ああ|NULL | |2 |いい|NULL | |3 |うう|NULL | テーブル:ans(key:q_id、a_id) |q_id|a_id|memo|del_id| +------------------------+ |2 |1 |かか|delete| |2 |2 |きき|delete| |3 |1 |くく|NULL | |3 |2 |けけ|NULL | |3 |3 |ここ|NULL | 上記のようなテーブルがあります。 ans>q_idがないか、ans>del_idがNULLのデータを取得したいと考えています。 期待する結果は・・・ |q_id|memo|del_id| +------------------+ |1 |ああ|NULL | |2 |いい|NULL | 以下のようなクエリを発行した場合 q_id=1 は取得できるのですが、q_id=2 が取得できません。 select q.* from qes q left join ans a using(q_id) where a.a_id is NULL and a.del_id is NULL group by q.q_id order by q.q_id ASC temporary table を使用しないとできないでしょうか。 ご教示よろしくお願いいたします。 <環境> MySQL:3.23.56 PHP:Version 4.3.1

  • MySQL: 複数テーブルのcount

    複数テーブルの総行数(count値)を取得したいのですが、下記だとテーブルA,B,Cの結果が バラバラに出力されてしまいます。 【入力条件】 mysql> select COUNT(*) AS 列ID from テーブルA      union all      select COUNT(*) AS 列ID from テーブルB      union all      select COUNT(*) AS 列ID from テーブルC; 【出力結果】       +-----+       | 列_ID |       +-----+       |  1  | ←テーブルAの合計:行数       |  2  | ←テーブルBの合計:行数       |  3  | ←テーブルCの合計:行数       +-----+ 総行数:6を一発で取得するには、どのようにしたらよろしいのでしょうか? 大変恐縮ですが、ご教授よろしくお願いいたいます。 <<MySQLのverは5,5です。

    • ベストアンサー
    • MySQL
  • 再投稿:フィールドの値をテーブル名&フィールド名にして参照したい

    すみません。若干記入ミスだったので再投稿します。 こちらにご解答お願いします。 TABLE_a ・Ta_id ・key_table ・key_field ・key_no TABLE_b ・Tb_id ・Tb_name TABLE_c ・Tc_id ・Tc_name と3つのテーブルがあり、 key_tableに「TABLE_b」、key_fieldに「Tb_id」が入ってて、 TABLE_aとTABLE_bを select の left join して抽出したい場合、 どういうSQL文になるのでしょうか。 select * from TABLE_a left join case key_table when 'TABLE_b' then 'TABLE_b' when 'TABLE_c' then 'TABLE_c' end on 'TABLE_a.key_field'.key_no = case key_table when 'TABLE_b' then ''TABLE_a.key_table'.Tb_id' when 'TABLE_c' then ''TABLE_a.key_table'.Tc_id' end ; とやってみたのですが、うまくできませんでした。 ご教示お願いします。

  • MySQL 複数フィールドで不一致の抽出

    ジャンル  id ジャンル名 日 数 id ----+---------------+--------------+---------+------- 001 ワンピース 20110518 10 a001 001 ワンピース 20110518 6 a002 002 アクセサリー 20110518 5 b002 仮に、このようなデータがあったとします。 数時間後には、↓のように変更がかかって送られてきます。 001 ワンピース 20110519 7 a001 001 ワンピース 20110518 6 a002 002 アクセサリー 20110519 9 b002 データ配布元の問題で、内容が更新された時点で、まだデータが確定していないものは、前日のデータが混ざって送られてきます。 この仕様を改良することは、残念ながら全く不可能です。 しかし、このデータをそのままテーブルに取り込んでしまうと、当然、2行目が重複してテーブルに収まってしまい、その後のデータ抽出に支障がでます。 例の場合でいえば、既に存在している2行目のデータを捨て、1行目と3行目のみを抽出する方法を探しています。 そこで、全部のデータを持つのをテーブル1とし、新しく着いたデータ(0519を含む方)をテーブル2に一時保管て、 SELECT テーブル2.ジャンルid, テーブル2.ジャンル名, テーブル2.日, テーブル2.数, テーブル2.ID FROM テーブル2 LEFT JOIN テーブル1 ON (テーブル2.ID = テーブル1.ID) AND (テーブル2.数 = テーブル1.数) AND (テーブル2.日 = テーブル1.日) AND (テーブル2.ジャンルid = テーブル1.ジャンルid) WHERE (((テーブル1.ジャンルid) Is Null)); と不一致SQLをAccessで行ったところ、1行目と3行目までが抽出できました。 ジャンルid、日、数、id が一致しないものを取りだすという不一致クエリの改造です。 ところが、同じSQLを、本番であるMySQLで行ったところ、データが抽出できす、反応が無くなってしまいます。 サンプルでは件数を絞りましたが、実際には1回分のデータが1万件近くあり、さらにメインテーブルは60万件ほどになるため、量が多すぎるためとも思いますが、4時間経ってもクエリの結果が返って来ないのは、MySQLとなにか合わないのではないかと思います。 MySQLで、上記と同じく、ジャンルid、日、数、id の全てが一致しないデータを抽出する事は可能でしょうか? ちなみに、MySQLテーブルでは、idの前にインクリメントのフィールドを置き、インデックスもインクリメントのフィールドで作成してあります。 よろしくお願いします。

  • MySQLでLEFT JOIN

    MySQL4.0.26でテーブルの左外部結合がしたいです。 左テーブルAと 右テーブルBをWHERE句で抽出したもの を結合することはできないのでしょうか? 考えた以下の式ではエラーが出てしまいます。 SELECT * FROM A LEFT JOIN ( SELECT * B WHERE id = 1 ) AS B2 ON A.id = B2.id

    • ベストアンサー
    • MySQL