トリガー データベースで特定のアクションが発生したときに自動的に実行される事前定義されたSQLコマンドです。 INSERT
の前または後に起動できます 、UPDATE
、またはDELETE
イベント。
トリガーは主にMySQLサーバーのソフトウェアロジックを維持するために使用され、いくつかの利点があります。
-
トリガーは、グローバルな運用を1か所に集中させるのに役立ちます。
-
クライアント側のコードを削減し、データベースサーバーへのラウンドトリップを最小限に抑えるのに役立ちます。
-
これらは、アプリケーションをさまざまなプラットフォーム間でよりスケーラブルにするのに役立ちます。
トリガーの一般的な使用例には、監査ログ、データベース値の事前計算(累積合計など)、複雑なデータの整合性と検証ルールの適用などがあります。
このガイドでは、次のことを学びます。
-
トリガーの構文はどのように構成されていますか。
-
他のデータベースイベントが発生する前に実行されるトリガーを作成する方法。
-
他のデータベースイベントが発生した後に実行されるトリガーを作成する方法。
-
トリガーを削除する方法。
始める前に
-
まだ行っていない場合は、Linodeアカウントとコンピュートインスタンスを作成します。 Linode入門とコンピューティングインスタンスの作成ガイドをご覧ください。
-
コンピューティングインスタンスのセットアップと保護ガイドに従って、システムを更新してください。また、タイムゾーンを設定し、ホスト名を構成し、制限付きユーザーアカウントを作成し、SSHアクセスを強化することもできます。
-
LinodeサーバーにインストールされたMySQLサーバーとクライアント。 MySQLのインストールガイドは、MySQLセクションのさまざまなディストリビューションで利用できます。
データベースを準備する
トリガーがどのように機能するかをよりよく理解するために、サンプルデータベースを作成し、それにサンプルデータを追加します。後で、概念実証の演習として、データベースにさまざまなトリガーを作成します。
-
まず、MySQLサーバーにログインします:
mysql -u root -p
次に、MySQLサーバーのrootパスワードを入力し、 Enterを押します。 続行します。
-
次に、以下に示すようなMySQLプロンプトが表示されます。
mysql >
-
test_database
を作成します 以下のコマンドを実行します:CREATE DATABASE test_database;
出力:
Query OK, 1 row affected (0.02 sec)
-
データベースに切り替えます:
USE test_database;
出力:
Database changed
-
データベースを選択したら、トリガーのデモンストレーションに使用するいくつかのテーブルを作成します。まず、
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)
-
次に、2つのレコードを
stores
に追加します 以下のコマンドを実行してテーブルを作成します:INSERT INTO stores (store_name) VALUES ('Philadelphia'); INSERT INTO stores (store_name) VALUES ('Galloway');
各コマンドの後に、次の出力が表示されます。
Query OK, 1 row affected (0.08 sec) ...
-
以下のコマンドを実行して、レコードを確認します。
SELECT * FROM stores;
出力:
+----------+--------------+ | store_id | store_name | +----------+--------------+ | 1 | Philadelphia | | 2 | Galloway | +----------+--------------+ 2 rows in set (0.01 sec)
-
次に、
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
の値を使用します 両方の店舗(フィラデルフィアとギャロウェー)で販売されている商品を意味します。
-
-
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) ...
-
以下のコマンドを実行して、製品が挿入されたかどうかを確認します。
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)
-
次に、商品の在庫状況が
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)
-
次に、
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)
-
最後に、
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_TIME
:BEFORE
のいずれか またはAFTER
。 -
TRIGGER_EVENT
:トリガーを呼び出すデータベースイベントを指定する必要があります:INSERT
、UPDATE
、または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
に挿入されるたびに、製品の小売価格が原価よりも高いことを確認します。 テーブル。そうしないと、データベースユーザーにエラーが発生します。
-
まだ
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に指示します。
-
-
上記のトリガーをテストするには、検証ルールに違反する商品を挿入してみてください:
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
トリガーを使用して値を読み取り専用にすることができます。これにより、悪意のあるユーザーや不注意なユーザーがレコードを不必要に変更するのを防ぐことができます。
-
新しい
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
)。不一致がある場合、例外がスローされます。 -
product_name_validator
を呼び出すには トリガーすると、ID1
で製品名の更新を試みることができます :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
を定義する方法を説明します。 ユーザーがテーブルから特定のレコードを削除できないようにするトリガー。
-
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
の値でマークされた製品を防ぎます 可用性列で削除されないようにします。 -
次に、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
に挿入します テーブル。このトリガーは、ビジネスロジックを適用するために使用されます。特に、さまざまな店舗での商品の在庫状況を定義するのに役立ちます。
-
以下のコードを実行して、
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つのストアで商品を利用できるようにするトリガーを指示します。
-
-
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');
-
次に、
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
の後にトリガーを起動することもできます イベント。このタイプのトリガーを活用して、店舗の価格の変化を経時的に追跡する方法を見ていきます。
-
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
を変更する必要はありません。 。 -
次に、以下のコマンドを実行して、最初の製品の価格を更新してみてください。
UPDATE products SET retail_price='36.75' WHERE product_id='1';
-
次に、
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
を使用して実現できます。 トリガー。
-
新しい
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
にログを記録します 将来の参照用の表。 -
次に、
products
から商品を削除します テーブルを作成し、トリガーが呼び出されるかどうかを確認します:DELETE FROM products WHERE product_id='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トリガーの構文と例