sql >> データベース >  >> RDS >> Mysql

列名を持つすべてのテーブルを選択し、その列を更新する方法

    いいえ、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 ;
    

    うまくいけば、それは私がもう少し詳細に与えた例を説明します。



    1. エラー:データソースが接続の確立を拒否しました、サーバーからのメッセージ:接続が多すぎます

    2. 2つのリモートデータベース間でMySQLデータベースを同期する方法(MySQLデータベースレプリケーション技術なし)

    3. SELECTINTOが機能しない

    4. 誰かがMagentosインデックス機能を詳細に説明できますか?