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

MySQLデータベースでのトリガーの操作-チュートリアル

    トリガー データベースで特定のアクションが発生したときに自動的に実行される事前定義されたSQLコマンドです。 INSERTの前または後に起動できます 、UPDATE 、またはDELETE イベント。

    トリガーは主にMySQLサーバーのソフトウェアロジックを維持するために使用され、いくつかの利点があります。

    • トリガーは、グローバルな運用を1か所に集中させるのに役立ちます。

    • クライアント側のコードを削減し、データベースサーバーへのラウンドトリップを最小限に抑えるのに役立ちます。

    • これらは、アプリケーションをさまざまなプラットフォーム間でよりスケーラブルにするのに役立ちます。

    トリガーの一般的な使用例には、監査ログ、データベース値の事前計算(累積合計など)、複雑なデータの整合性と検証ルールの適用などがあります。

    このガイドでは、次のことを学びます。

    • トリガーの構文はどのように構成されていますか。

    • 他のデータベースイベントが発生する前に実行されるトリガーを作成する方法。

    • 他のデータベースイベントが発生した後に実行されるトリガーを作成する方法。

    • トリガーを削除する方法。

    始める前に

    1. まだ行っていない場合は、Linodeアカウントとコンピュートインスタンスを作成します。 Linode入門とコンピューティングインスタンスの作成ガイドをご覧ください。

    2. コンピューティングインスタンスのセットアップと保護ガイドに従って、システムを更新してください。また、タイムゾーンを設定し、ホスト名を構成し、制限付きユーザーアカウントを作成し、SSHアクセスを強化することもできます。

    3. LinodeサーバーにインストールされたMySQLサーバーとクライアント。 MySQLのインストールガイドは、MySQLセクションのさまざまなディストリビューションで利用できます。

    データベースを準備する

    トリガーがどのように機能するかをよりよく理解するために、サンプルデータベースを作成し、それにサンプルデータを追加します。後で、概念実証の演習として、データベースにさまざまなトリガーを作成します。

    1. まず、MySQLサーバーにログインします:

      mysql -u root -p
      

      次に、MySQLサーバーのrootパスワードを入力し、 Enterを押します。 続行します。

    2. 次に、以下に示すようなMySQLプロンプトが表示されます。

      mysql >
    3. test_databaseを作成します 以下のコマンドを実行します:

      CREATE DATABASE test_database;
      

      出力:

      Query OK, 1 row affected (0.02 sec)
    4. データベースに切り替えます:

      USE test_database;
      

      出力:

      Database changed
    5. データベースを選択したら、トリガーのデモンストレーションに使用するいくつかのテーブルを作成します。まず、storesを作成します テーブル。この表には、架空のビジネスが運営されている2つのサンプルストア/オフィスに関する情報が含まれています。

      CREATE TABLE stores
      (
      store_id BIGINT PRIMARY KEY AUTO_INCREMENT,
      store_name VARCHAR(50)
      ) ENGINE=InnoDB;
      

      出力:

      Query OK, 0 rows affected (0.07 sec)
    6. 次に、2つのレコードをstoresに追加します 以下のコマンドを実行してテーブルを作成します:

      INSERT INTO stores (store_name) VALUES ('Philadelphia');
      INSERT INTO stores (store_name) VALUES ('Galloway');
      

      各コマンドの後に、次の出力が表示されます。

      Query OK, 1 row affected (0.08 sec)
      ...
    7. 以下のコマンドを実行して、レコードを確認します。

      SELECT * FROM stores;
      

      出力:

      +----------+--------------+
      | store_id | store_name   |
      +----------+--------------+
      |        1 | Philadelphia |
      |        2 | Galloway     |
      +----------+--------------+
      2 rows in set (0.01 sec)
    8. 次に、productsを作成します テーブル。テーブルには、ストアで提供されているさまざまな商品が含まれます:

      CREATE TABLE products
      (
      product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
      product_name VARCHAR(40),
      cost_price DOUBLE,
      retail_price DOUBLE,
      availability VARCHAR(5)
      ) ENGINE=InnoDB;
      

      出力:

      Query OK, 0 rows affected (0.13 sec)
      • 各製品は、product_idによって一意に識別されます 。

      • product_name フィールドはアイテムの名前を指定します。

      • cost_price およびretail_price フィールドはそれぞれ購入価格と販売価格を決定します。

      • availability 列は、さまざまな店舗での商品の在庫状況を定義します。製品がローカルストア(フィラデルフィア)でのみ入手可能な場合は、LOCALで示します。 価値。それ以外の場合は、ALLの値を使用します 両方の店舗(フィラデルフィアとギャロウェー)で販売されている商品を意味します。

    9. productsにサンプルデータを追加します テーブル:

      INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('WIRELESS MOUSE', '18.23', '30.25','ALL');
      
      INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('8 MP CAMERA', '60.40', '85.40','ALL');
      
      INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('SMART WATCH', '189.60', '225.30','LOCAL');
      

      各挿入コマンドの後に、以下に示す出力が表示されます。

      Query OK, 1 row affected (0.02 sec)
      ...
    10. 以下のコマンドを実行して、製品が挿入されたかどうかを確認します。

      SELECT * FROM products;
      

      出力:

      +------------+----------------+------------+--------------+--------------+
      | product_id | product_name   | cost_price | retail_price | availability |
      +------------+----------------+------------+--------------+--------------+
      |          1 | WIRELESS MOUSE |      18.23 |        30.25 | ALL          |
      |          2 | 8 MP CAMERA    |       60.4 |         85.4 | ALL          |
      |          3 | SMART WATCH    |      189.6 |        225.3 | LOCAL        |
      +------------+----------------+------------+--------------+--------------+
      3 rows in set (0.00 sec)
    11. 次に、商品の在庫状況がproducts_to_storesという名前の別のテーブルにマッピングされます。 。このテーブルは、product_idを参照するだけです。 productsから テーブルとstore_id storesから アイテムが利用可能なテーブル。

      products_to_storesを作成します 以下のコードを実行してテーブルを作成します:

      CREATE TABLE products_to_stores
      (
      ref_id BIGINT PRIMARY KEY AUTO_INCREMENT,
      product_id BIGINT,
      store_id BIGINT
      ) ENGINE=InnoDB;
      

      出力:

      Query OK, 0 rows affected (0.14 sec)
    12. 次に、archived_productsを作成します テーブル。この表には、今後の参照用に削除された製品に関する情報が保持されます:

      CREATE TABLE archived_products
      (
      product_id BIGINT PRIMARY KEY ,
      product_name VARCHAR(40),
      cost_price DOUBLE,
      retail_price DOUBLE,
      availability VARCHAR(5)
      ) ENGINE=InnoDB;
      

      出力:

      Query OK, 0 rows affected (0.14 sec)
    13. 最後に、products_price_historyを作成します 時間の経過とともに各製品のさまざまな価格を追跡するための表:

      CREATE TABLE products_price_history
      (
      product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
      price_date DATETIME,
      retail_price DOUBLE
      ) ENGINE=InnoDB;
      

      出力:

      Query OK, 0 rows affected (0.14 sec)

    データベース構造が整ったら、最初のサンプルを作成するために、MySQLデータベーストリガーの基本的な構文を学習できます。

    トリガー構文

    前に示したように、トリガーは、データベースでSQLコマンドが実行される前または後に自動的に起動されます。トリガーを作成するための基本的な構文は次のとおりです。

    CREATE TRIGGER TRIGGER_NAME
    
    TRIGGER_TIME TRIGGER_EVENT
    
    ON TABLE_NAME FOR EACH ROW
    
    [TRIGGER BODY];
    
    • TRIGGER_NAME :各トリガーには一意の名前を付ける必要があり、ここで定義する必要があります。

    • TRIGGER_TIMEBEFOREのいずれか またはAFTER

    • TRIGGER_EVENT :トリガーを呼び出すデータベースイベントを指定する必要があります:INSERTUPDATE 、またはDELETE

    • TRIGGER BODY :これは、トリガーによって実行される実際のSQLコマンドを指定します。

    トリガー本体に複数のSQLステートメントがある場合は、それをBEGIN...ENDで囲む必要があります。 ブロック。また、DELIMITERを一時的に変更する必要があります これは、トリガー本体の終わりを新しい値に通知します。これにより、本文内のステートメントがMySQLクライアントによって時期尚早に解釈されないようになります。この例は次のようになります:

    DELIMITER &&
    
    CREATE TRIGGER TRIGGER_NAME
    
    TRIGGER_TIME TRIGGER_EVENT
    
    ON TABLE_NAME FOR EACH ROW
    
    BEGIN
    
    [TRIGGER BODY]
    
    END &&
    
    DELIMITER ;
    
    注 この例の最後の行は、DELIMITERを変更します デフォルトの;に戻します 値。

    イベントトリガーの前に作成

    このセクションでは、データベース操作の前に起動されるさまざまなタイプのトリガーについて説明します。これには、BEFORE INSERTが含まれます 、BEFORE UPDATE 、およびBEFORE DELETE トリガー。

    挿入前トリガーの作成

    最初のBEFORE INSERTを作成します 引き金。トリガーは、アイテムがproductsに挿入されるたびに、製品の小売価格が原価よりも高いことを確認します。 テーブル。そうしないと、データベースユーザーにエラーが発生します。

    1. まだmysql >にいる間 プロンプトが表示されたら、以下のコマンドを入力します:

      DELIMITER $$
      
      CREATE TRIGGER price_validator
      
      BEFORE INSERT
      
      ON products FOR EACH ROW
      
      IF NEW.cost_price>=NEW.retail_price
      
      THEN
      
      SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Retail price must be greater than cost price.';
      
      END IF $$
      
      DELIMITER ;
      
      • 上記のコードはトリガー名を定義します(price_validator )、時間(BEFORE )、イベント(INSERT )、およびテーブル(products )影響を受ける。

      • トリガーはNEWを使用します cost_priceを確認するためのキーワード およびretail_price productsにレコードが挿入される前 テーブル、IF...THEN...END IFを使用 ステートメント。

      • cost_priceの場合 retail price以上 、トリガーは、エラーを修正するようにユーザーに指示するカスタム例外をスローするようにMySQLに指示します。

    2. 上記のトリガーをテストするには、検証ルールに違反する商品を挿入してみてください:

      INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');
      

      出力:

      ERROR 1644 (45000): Retail price must be greater than cost price.

      retail_priceが原因で、上記の挿入コマンドは失敗するはずです。 (144.00)はcost_priceより大きくありません (145.00)。

    更新前トリガーの作成

    次に、BEFORE UPDATEを作成します 引き金。このトリガーは、製品がデータベースに挿入されると、データベースユーザーが製品名を編集できないようにします。データベースで複数のユーザーが作業している場合は、BEFORE UPDATE トリガーを使用して値を読み取り専用にすることができます。これにより、悪意のあるユーザーや不注意なユーザーがレコードを不必要に変更するのを防ぐことができます。

    1. 新しいproduct_name_validatorを作成します 以下のコマンドでトリガーします:

      DELIMITER $$
      
      CREATE TRIGGER product_name_validator
      
      BEFORE UPDATE
      
      ON products FOR EACH ROW
      
      IF NEW.product_name<>OLD.product_name
      
      THEN
      
      SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Product name is read-only and it can not be changed.';
      
      END IF $$
      
      DELIMITER ;
      

      このトリガーは、新しいproduct_nameの値を比較します (NEW.product_name )およびデータベースにすでに存在する古い名前(OLD.product_name )。不一致がある場合、例外がスローされます。

    2. product_name_validatorを呼び出すには トリガーすると、ID 1で製品名の更新を試みることができます :

      UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';
      

      出力:

      ERROR 1644 (45000): Product name is read-only and it can not be changed.

    削除前トリガーの定義

    このセクションでは、BEFORE DELETEを定義する方法を説明します。 ユーザーがテーブルから特定のレコードを削除できないようにするトリガー。

    1. prevent_deleteを作成するには トリガーし、以下のコマンドを実行します:

      DELIMITER $$
      
      CREATE TRIGGER prevent_delete
      
      BEFORE DELETE
      
      ON products FOR EACH ROW
      
      IF OLD.availability='ALL'
      
      THEN
      
      SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'The product can not be deleted because it is available in ALL stores.';
      
      END IF $$
      
      DELIMITER ;
      

      このトリガーは、ALLの値でマークされた製品を防ぎます 可用性列で削除されないようにします。

    2. 次に、productsテーブルから最初の製品を削除して、トリガーが呼び出されるかどうかを確認します。

      DELETE FROM products WHERE product_id='1';
      

      出力:

      ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores.

    データベース操作の前に呼び出されるさまざまなトリガーについて見てきました。次に、データベースイベントの後に発生する他のタイプのトリガーを調べます。

    イベントトリガー後の作成

    実稼働環境では、データベースイベントが発生した後にいくつかのトリガーを自動的に実行したい場合があります(たとえば、レコードを別のテーブルに挿入するなど)。以下の例は、これらの種類のトリガーをサンプルデータベースで使用する方法を示しています。

    挿入後トリガーの作成

    この例では、product_availabilityという名前のトリガーを作成します マッピングレコードをproducts_to_storesに挿入します テーブル。このトリガーは、ビジネスロジックを適用するために使用されます。特に、さまざまな店舗での商品の在庫状況を定義するのに役立ちます。

    1. 以下のコードを実行して、product_availabilityを作成します 引き金。トリガー本体には複数行のコードがあるため、BEGIN...ENDを使用します ブロック:

      DELIMITER $$
      
      CREATE TRIGGER product_availability
      
      AFTER INSERT
      
      ON products FOR EACH ROW
      
      BEGIN
      
      IF NEW.availability='LOCAL' then
      
      INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '1');
      
      ELSE
      
      INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '1');
      
      INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '2');
      
      END IF;
      
      END $$
      
      DELIMITER ;
      
      • アイテムがproductsに挿入されているとき テーブルの場合、トリガーはavailabilityをチェックします フィールド。

      • LOCALでマークされている場合 価値、製品は1つの店舗でのみ利用可能になります。

      • その他の値は、以前に作成した2つのストアで商品を利用できるようにするトリガーを指示します。

    2. product_availabilityを確認するには トリガーを実行して、2つのレコードを製品テーブルに挿入します。

      INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('BLUETOOTH KEYBOARD', '17.60', '23.30','LOCAL');
      INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('DVB-T2 RECEIVE', '49.80', '53.40','ALL');
      
    3. 次に、products_to_storesにクエリを実行します テーブル:

      SELECT * FROM products_to_stores;
      

      以下に示すような出力が表示されます。

      +--------+------------+----------+
      | ref_id | product_id | store_id |
      +--------+------------+----------+
      |      1 |          4 |        1 |
      |      2 |          5 |        1 |
      |      3 |          5 |        2 |
      +--------+------------+----------+
      3 rows in set (0.00 sec)

    更新後のトリガーの定義

    UPDATEの後にトリガーを起動することもできます イベント。このタイプのトリガーを活用して、店舗の価格の変化を経時的に追跡する方法を見ていきます。

    1. product_history_updaterを作成します 以下のコマンドを実行してトリガーします:

      CREATE TRIGGER product_history_updater
      
      AFTER UPDATE
      
      ON products FOR EACH ROW
      
      INSERT INTO products_price_history (product_id, price_date, retail_price) VALUES (OLD.product_id, NOW(), NEW.retail_price);
      

      このトリガーは、商品のretail_priceへの変更を記録します products_price_history内 テーブル。

      注 前の例とは異なり、このトリガーの本体にはステートメントが1つしかないため、DELIMITERを変更する必要はありません。 。
    2. 次に、以下のコマンドを実行して、最初の製品の価格を更新してみてください。

      UPDATE products SET retail_price='36.75' WHERE product_id='1';
      
    3. 次に、products_price_historyにクエリを実行します 価格変更がログに記録されたかどうかを確認するための表:

      SELECT * FROM products_price_history;
      

      トリガーが期待どおりに機能した場合は、次の出力が得られるはずです。

      +------------+---------------------+--------------+
      | product_id | price_date          | retail_price |
      +------------+---------------------+--------------+
      |          1 | 2020-01-28 11:46:21 |        36.75 |
      +------------+---------------------+--------------+
      1 row in set (0.00 sec)

    削除後トリガーの作成

    場合によっては、データベースで特定のアクションが発生した後に削除操作をログに記録したいことがあります。これは、AFTER DELETEを使用して実現できます。 トリガー。

    1. 新しいproduct_archiverを作成します 以下のコマンドでトリガーします:

      CREATE TRIGGER product_archiver
      
      AFTER DELETE
      
      ON products FOR EACH ROW
      
      INSERT INTO archived_products (product_id, product_name, cost_price, retail_price, availability) VALUES (OLD.product_id, OLD.product_name, OLD.cost_price, OLD.retail_price, OLD.availability);
      

      このトリガーは、削除された製品をarchived_productsという名前の別のテーブルにアーカイブします 。メインのproductsからアイテムが削除されたとき テーブルの場合、トリガーは自動的にarchived_productsにログを記録します 将来の参照用の表。

    2. 次に、productsから商品を削除します テーブルを作成し、トリガーが呼び出されるかどうかを確認します:

      DELETE FROM products WHERE product_id='3';
      
    3. ここで、archived_productsを確認すると 表には、1つのレコードが表示されます:

      SELECT * FROM archived_products;
      

      出力:

      +------------+--------------+------------+--------------+--------------+
      | product_id | product_name | cost_price | retail_price | availability |
      +------------+--------------+------------+--------------+--------------+
      |          3 | SMART WATCH  |      189.6 |        225.3 | LOCAL        |
      +------------+--------------+------------+--------------+--------------+
      1 row in set (0.00 sec)

    トリガーの削除

    さまざまなタイプのトリガーと、それらを実稼働環境で使用する方法を見てきました。データベースからトリガーを削除したい場合があります。

    以下の構文を使用して、トリガーを使用したくない場合は、トリガーを削除できます。

    DROP TRIGGER IF EXISTS TRIGGER_NAME;
    
    IF EXISTS キーワードは、トリガーが存在する場合にのみトリガーを削除するオプションのパラメーターです。

    たとえば、product_archivingを削除するには 上で定義したトリガーは、次のコマンドを使用します:

    DROP TRIGGER IF EXISTS product_archiver;
    

    出力:

    Query OK, 0 rows affected (0.00 sec)
    注意 トリガーに関連付けられているテーブルを削除するときは注意してください。 MySQLデータベースからテーブルが削除されると、関連するトリガーも自動的に削除されます。

    詳細情報

    このトピックの詳細については、次のリソースを参照してください。これらは有用であることを期待して提供されていますが、外部でホストされている資料の正確性や適時性を保証することはできません。

    • MySQLトリガーの構文と例

    1. MySQLで空の値を許可する一意の制約

    2. OracleのINSERTステートメント

    3. MySQLとMariaDBのすべてのデータベースを一覧表示および表示するSQLコマンド

    4. Log()がPostgreSQLでどのように機能するか