MySQL、1つのクエリで複数のテーブルを更新


132

3つのテーブルを更新する関数がありますが、3つのクエリを使用してこれを実行しています。良い実践のためにもっと便利な方法を使いたいと思います。

1つのクエリでMySQLの複数のテーブルを更新するにはどうすればよいですか?


3
生成されたコードの例を提供できますか?テーブル間に共通のキーはありますか?
ジョナサンデイ

回答:


451

二つのテーブルの場合を取る、BooksOrders。ケースでは、我々が特定の順序で本の数を増やすOrder.ID = 1002にはOrders、我々はまた、削減する必要があるテーブル内の同じ番号で当社の株式で利用可能な図書の総数いるBooksテーブル。

UPDATE Books, Orders
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE
    Books.BookID = Orders.BookID
    AND Orders.OrderID = 1002;

SQLクエリに "LIMIT"を含める場合、LIMIT 1またはLIMIT 2と言う必要がありますか?
Bluedayz 2014

2
トランザクションと比較してこれを行う利点は何ですか?ありがとう!
ポールコン2014年

2
@paulkon、トランザクションを使用する場合、トランザクションのいずれかのプロシージャが失敗した場合にロールバックを使用できるようにする必要があるため、多くのオーバーヘッドが発生すると思います。
Thijs Riezebeek 2015

27
このクエリを使用する際の一般的な警告。WHERE句は、テーブルごとに個別に評価されます。Books.BookID = Orders.BookIDは非常に重要です。これがないと、Booksテーブルの更新は、指定されたIDを持つ行だけでなく、すべての行に対して行われます。一部のレッスンは困難な方法で学習されましたが、これは恐ろしい方法で学習されました。
nheimann1 2015年

1
@ nheimann1そして、まさにそのために、常にANSIの「内部結合」構文を使用することを人々に勧めています。その状態を忘れて完全なデカルト結合を取得するのは簡単です。
fool4jesus

77
UPDATE t1
INNER JOIN t2 ON t2.t1_id = t1.id
INNER JOIN t3 ON t2.t3_id = t3.id
SET t1.a = 'something',
    t2.b = 42,
    t3.c = t2.c
WHERE t1.a = 'blah';

これが更新する内容を確認するには、これをselectステートメントに変換します。例:

SELECT t2.t1_id, t2.t3_id, t1.a, t2.b, t2.c AS t2_c, t3.c AS t3_c
FROM t1
INNER JOIN t2 ON t2.t1_id = t1.id
INNER JOIN t3 ON t2.t3_id = t3.id
WHERE t1.a = 'blah';

他の回答と同じテーブルを使用した例:

SELECT Books.BookID, Orders.OrderID,
    Orders.Quantity AS CurrentQuantity,
    Orders.Quantity + 2 AS NewQuantity,
    Books.InStock AS CurrentStock,
    Books.InStock - 2 AS NewStock
FROM Books
INNER JOIN Orders ON Books.BookID = Orders.BookID
WHERE Orders.OrderID = 1002;

UPDATE Books
INNER JOIN Orders ON Books.BookID = Orders.BookID
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE Orders.OrderID = 1002;

編集:

楽しみのために、もう少し興味深いものを追加しましょう。

のテーブルbooksとのテーブルがあるとしますauthors。あなたbooksが持っていauthor_idます。しかし、データベースが最初に作成されたとき、外部キー制約は設定されておらず、後でフロントエンドコードのバグにより、一部の書籍に無効なauthor_ids が追加されていました。DBAとして、これらのすべてbooksを調べて何がauthor_id必要かを確認する必要はないので、データキャプチャーがを正しい方向に向けるように修正することを決定booksしますauthors。しかし、本が多すぎて1冊を読むことができないためauthor_id、実際に対応するを持っている本authorが正しいことを知っているとしましょう。存在しないものだけですauthor_id無効です。ユーザーが本の詳細を更新するためのインターフェースはすでにあり、開発者はこの問題のためにそれを変更したくありません。ただし、既存のインターフェースはを実行するINNER JOIN authors、したがって、無効な著者のある本はすべて除外されます。

あなたができることはこれです: "Unknown author"のような偽の著者レコードを挿入します。次に、author_id、不明な作成者を指すようにすべての不良レコードをます。次に、データキャプチャは、著者が「不明な著者」に設定されているすべての書籍を検索し、正しい著者を検索して修正できます。

不明な作成者を指すようにすべての不良レコードをどのように更新しますか?このように(不明な作成者author_idが99999であると想定):

UPDATE books
LEFT OUTER JOIN authors ON books.author_id = authors.id
SET books.author_id = 99999
WHERE authors.id IS NULL;

上記は、不明な作成者を含む更新booksも行いますNULL author_id。それが必要ない場合は、もちろんを追加できAND books.author_id IS NOT NULLます。


35

次のような結合を使用して、1つのクエリでもこれを行うことができます。

UPDATE table1,table2 SET table1.col=a,table2.col2=b
WHERE items.id=month.id;

もちろん、この1つのクエリを送信します。結合について詳しくは、http//dev.mysql.com/doc/refman/5.0/en/join.htmlを参照してください。ここで読むことができる複数のテーブル更新の注文と制限には、いくつかの制限があります:http : //dev.mysql.com/doc/refman/5.0/en/update.html(ctrl + f "join")。


これを「結合」と呼ぶのは少し寛大です;-)
underscore_d

2

通常、これがストアドプロシージャの目的です。複数のSQLステートメントをシーケンスで実装します。ロールバックを使用すると、データの一貫性を保つために、それらが1つの作業単位として扱われるようにすることができます。


プロシージャはどこに記述しますか?例を挙げていただけませんか?
アダムスキー、2010

1
アトミック性の必要性を説明するための賛成票-ストアドプロシージャを使用しても一貫性が保証されるだけではなく、トランザクションを使用する必要があることを認識することも重要です。同様に、トランザクションは、同じ接続を介して実行される場合、ストアドプロシージャを使用せずに実行できます。この場合、複数テーブルの更新を使用するとさらに効果的です。
Duncan

2

複数のクエリとは、次のように複数のSQLステートメントを意味します。

UPDATE table1 SET a=b WHERE c;
UPDATE table2 SET a=b WHERE d;
UPDATE table3 SET a=b WHERE e;

または次のように複数のクエリ関数呼び出し:

mySqlQuery(UPDATE table1 SET a=b WHERE c;)
mySqlQuery(UPDATE table2 SET a=b WHERE d;)
mySqlQuery(UPDATE table3 SET a=b WHERE e;)

前者はすべて、1つのmySqlQuery呼び出しを使用して実行できます。それが実現したい場合は、次の方法でmySqlQuery関数を呼び出すだけです。

mySqlQuery(UPDATE table1 SET a=b WHERE c; UPDATE table2 SET a=b WHERE d; UPDATE table3 SET a=b WHERE e;)

これにより、1つのmySqlQuery()呼び出しで3つすべてのクエリが実行されます。


mySqlQuery()はカスタム関数ですか、組み込み関数ですか?これについてもっと知りたい。
Debashis 2012

3
クエリ関数が毎回新しい接続を開く場合を除いて、3つのクエリを個別に送信するか、複数のクエリとして送信しても、大きな違いはありません。サーバーサイド実行の観点からは、同じことです
Duncan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.