いいえ、1つのステートメントではありません。
Foo
という名前の列を含むすべてのテーブルの名前を取得するには :
SELECT table_schema, table_name
FROM information_schema.columns
WHERE column_name = 'Foo'
次に、テーブルごとにUPDATEステートメントが必要になります。 (1つのステートメントで複数のテーブルを更新することは可能ですが、それは(不要な)クロス結合である必要があります。)各テーブルを個別に実行することをお勧めします。
動的SQLを使用して、MySQLストアドプログラム(例:PROCEDURE)でUPDATEステートメントを実行できます
DECLARE sql VARCHAR(2000);
SET sql = 'UPDATE db.tbl SET Foo = 0';
PREPARE stmt FROM sql;
EXECUTE stmt;
DEALLOCATE stmt;
information_schema.tablesからの選択のカーソルを宣言すると、カーソルループを使用して動的な UPDATE
を処理できます。 返された各table_nameのステートメント。
DECLARE done TINYINT(1) DEFAULT FALSE;
DECLARE sql VARCHAR(2000);
DECLARE csr FOR
SELECT CONCAT('UPDATE `',c.table_schema,'`.`',c.table_name,'` SET `Foo` = 0') AS sql
FROM information_schema.columns c
WHERE c.column_name = 'Foo'
AND c.table_schema NOT IN ('mysql','information_schema','performance_schema');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN csr;
do_foo: LOOP
FETCH csr INTO sql;
IF done THEN
LEAVE do_foo;
END IF;
PREPARE stmt FROM sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP do_foo;
CLOSE csr;
(これは例の大まかな概要であり、構文のチェックやテストは行われていません。)
フォローアップ
上記の回答でおそらく見過ごされていたいくつかのアイデアについての簡単なメモ。
列Foo
を含むテーブルの名前を取得するには 、 information_schema.columns
からクエリを実行できます テーブル。 (これは、MySQL information_schema
で提供されているテーブルの1つです。 データベース。)
複数のデータベースにテーブルがある可能性があるため、table_nameはテーブルを識別するのに十分ではありません。テーブルがどのデータベースにあるかを知る必要があります。「usedb
をいじくり回すのではなく、 " UPDATE
を実行する前のステートメント 、テーブル UPDATE db.mytable SET Foo ...
を参照するだけです。 。
information_schema.columns
のクエリを使用できます 先に進み、UPDATEステートメント用に作成する必要のある部分を連結(連結)し、SELECTに、列 Foo
を更新するために実行する必要のある実際のステートメントを返すようにします。 、基本的にこれ:
UPDATE `mydatabase`.`mytable` SET `Foo` = 0
ただし、 table_schema
の値に置き換えたいと思います およびtable_name
mydatabase
の代わりに およびmytable
。このSELECTを実行すると
SELECT 'UPDATE `mydatabase`.`mytable` SET `Foo` = 0' AS sql
これにより、単一の列を含む単一の行が返されます(列の名前はたまたま sql
です。 、ただし、列の名前は重要ではありません)。列の値は単なる文字列になります。しかし、返される文字列は、たまたま実行できるSQLステートメントです(願っています)。
その文字列を細かく分割し、CONCATを使用してそれらを元に戻しても、同じことがわかります。たとえば、
SELECT CONCAT('UPDATE `','mydatabase','`.`','mytable','` SET `Foo` = 0') AS sql
そのクエリを、 information_schema.columns
に対して実行するステートメントのモデルとして使用できます。 。 'mydatabase'
を置き換えます および'mytable'
information_schema.columns
の列への参照 データベースとtable_nameを提供するテーブル。
SELECT CONCAT('UPDATE `',c.table_schema,'`.`',c.table_name,'` SET `Foo` = 0') AS sql
FROM information_schema.columns
WHERE c.column_name = 'Foo'
私たちが絶対に行っていないデータベースがいくつかあります 更新したい...mysql
、 information_schema
、 performance_schema
。更新するテーブルを含むデータベースをホワイトリストに登録する必要があります
AND c.table_schema IN ('mydatabase','anotherdatabase')
-または -絶対に更新したくないデータベースをブラックリストに登録する必要があります
AND c.table_schema NOT IN ('mysql','information_schema','performance_schema')
そのクエリを実行できます( ORDER BY
を追加できます 行を特定の順序で返す場合)、返されるのは、実行するステートメントを含むリストです。その文字列のセットをプレーンテキストファイル(ヘッダー行と追加の書式設定を除く)として保存し、各行の最後にセミコロンを追加すると、 mysql>
> コマンドラインクライアント。
(上記のいずれかがわかりにくい場合は、お知らせください。)
次の部分はもう少し複雑です。この残りの部分では、SELECTからの出力をプレーンテキストファイルとして保存し、 mysql
からのステートメントを実行する代わりの方法を扱います。 コマンドラインクライアント。
MySQLは、基本的に任意のを実行できる機能/機能を提供します。 MySQLストアドプログラム(たとえば、ストアドプロシージャ。これから使用する機能は動的SQL と呼ばれます)のコンテキストでのSQLステートメントとしての文字列 。
動的SQLを使用するには 、ステートメント PREPARE
を使用します 、 EXECUTE
およびDEALLOCATEPREPARE
。 (割り当て解除は厳密には必要ありません。使用しない場合はMySQLによってクリーンアップされますが、とにかく実行することをお勧めします。)
繰り返しますが、動的SQL 利用可能のみ MySQLストアドプログラムのコンテキストで。これを行うには、実行するSQLステートメントを含む文字列が必要です。簡単な例として、これがあったとしましょう:
DECLARE str VARCHAR(2000);
SET str = 'UPDATE mytable SET mycol = 0 WHERE mycol < 0';
str
のコンテンツを取得するには SQLステートメントとして評価および実行される場合、基本的な概要は次のとおりです。
PREPARE stmt FROM str;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
次の複雑な部分は、SQLステートメントとして実行する文字列値を取得するために実行しているクエリと一緒にそれをまとめることです。そのために、カーソルループを作成します。そのための基本的な概要は、SELECTステートメントを使用することです。
SELECT bah FROM humbug
そしてそれをカーソル定義に変えます:
DECLARE mycursor FOR SELECT bah FROM humbug ;
それを実行して、返される行をループします。ステートメントを実行して結果セットを準備するには、カーソルを「開きます」
OPEN mycursor;
それが終わったら、結果セットをリリースするために「閉じる」を発行します。これにより、MySQLサーバーは、それがもう必要ないことを認識し、クリーンアップして、それに割り当てられたリソースを解放できます。
CLOSE mycursor;
ただし、カーソルを閉じる前に、結果セットを「ループ」して各行をフェッチし、その行で何かを実行する必要があります。結果セットからプロシージャ変数に次の行を取得するために使用するステートメントは次のとおりです。
FETCH mycursor INTO some_variable;
行を変数にフェッチする前に、変数を定義する必要があります。例:
DECLARE some_variable VARCHAR(2000);
カーソル(SELECTステートメント)は1つの列のみを返すため、必要な変数は1つだけです。さらに列がある場合は、列ごとに変数が必要になります。
最終的に、結果セットから最後の行をフェッチします。次のものをフェッチしようとすると、MySQLはエラーをスローします。
他のプログラミング言語では、 while
を実行できます ループし、行をフェッチして、すべての行を処理したらループを終了します。 MySQLはもっと難解です。ループを実行するには:
mylabel: LOOP
-- do something
END LOOP mylabel;
そのループには「出口」がないため、それ自体が非常に細かい無限ループになります。幸い、MySQLは LEAVE
を提供してくれます ループを終了する方法としてのステートメント。通常、最初にループに入るときにループを終了したくないので、通常、ループを終了する必要があるかどうかを判断するために使用する条件付きテストがあります。再びループ。
mylabel: LOOP
-- do something useful
IF some_condition THEN
LEAVE mylabel;
END IF;
END LOOP mylabel;
この例では、結果セットのすべての行をループするため、 FETCH
を配置します。 ループ内の最初のステートメント(私たちがやりたいこと)
結果セットの最後の行を超えてフェッチしようとしたときにMySQLがスローするエラーと、条件付きテストとの間のリンクを取得するには、終了する必要があるかどうかを判断する必要があります...
MySQLは、 CONTINUE HANDLER
を定義する方法を提供します (実行したいステートメント)エラーがスローされたとき...
DECLARE CONTINUE HANDLER FOR NOT FOUND
実行するアクションは、変数をTRUEに設定することです。
SET done = TRUE;
SETを実行する前に、変数を定義する必要があります。
DECLARE done TINYINT(1) DEFAULT FALSE;
これで、LOOPを変更して、 done
かどうかをテストできます。 終了条件として変数がTRUEに設定されているため、ループは次のようになります。
mylabel: LOOP
FETCH mycursor INTO some_variable;
IF done THEN
LEAVE mylabel;
END IF;
-- do something with the row
END LOOP mylabel;
「行で何かをする」とは、 some_variable
の内容を取得する場所です。 そしてそれで何か役に立つことをしなさい。カーソルは、SQLステートメントとして実行する文字列を返します。そしてMySQLは私たちに動的SQLを提供します そのために使用できる機能。
注:MySQLには、プロシージャ内のステートメントの順序に関するルールがあります。たとえば、 DECLARE
ステートメントは最初に来る必要があります。そして、CONTINUEHANDLERが最後に宣言されなければならないと思います。
繰り返しますが、カーソル および動的SQL 機能はのみ利用可能です ストアドプロシージャなどのMySQLストアドプログラムのコンテキストで。上記の例は、 bodyの例にすぎません。 手順の。
これをストアドプロシージャとして作成するには、次のようなものの一部として組み込む必要があります。
DELIMITER $$
DROP PROCEDURE IF EXISTS myproc $$
CREATE PROCEDURE myproc
NOT DETERMINISTIC
MODIFIES SQL DATA
BEGIN
-- procedure body goes here
END$$
DELIMITER ;
うまくいけば、それは私がもう少し詳細に与えた例を説明します。