アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

結構使えるMySQLのTrigger機能!

皆さん、ご無沙汰しております。
パソコン周辺機器にお金をかけはじめている笹亀です。

エンジニアはパソコンが商売道具なので、
やはり使いやすい物を使いたくなるのは自然な事ですね。
ご参考までに。。。
マウス  :Logicool MX Revolution(ビックカメラでポイントで購入
キーボード:Bluetooth Mac用キーボード(会社の人から売ってもらいましたw

今回はTriggerについてご紹介したいとおもいます。
Triggerとは、データの変更などのイベントによってあらかじめ指定した処理を自動的に実行する機能です。
最近使用しているデータベースには必ず備えてある機能です。
Oracle,Postgres,MySQLでも当たり前のようにあります。

実際にはどのようなときに使用するものなのでしょうか?
 ・特定のテーブルに対しての処理のログをとるため
 ・特定のテーブルのバックアップをとる
 ・子テーブルの内容が更新されたときに関連する親テーブルの情報を変更したいとき
このような場面ではTriggerを使うと便利かもしれません。

それでは、実際に今回はMySQLを使用してご説明していきたいとおもいます。
まずは、簡単なテーブルを作成しておきます。


■カテゴリテーブル
CREATE TABLE category_t (
  `id` int(10) unsigned NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `product_count` int(11) default 0,
  PRIMARY KEY  (`id`)
) DEFAULT CHARSET=utf8;
■商品テーブル
CREATE TABLE product_t (
  `id` int(10) unsigned NOT NULL auto_increment,
  `category_id` int(11) default NULL,
  `name` varchar(255) default NULL,
   PRIMARY KEY  (`id`)
) DEFAULT CHARSET=utf8;


カテゴリテーブルにはproduct_countというカテゴリに属する商品数をセットしておくフィールドを用意しておきます。
今回はproductテーブルにinsertしたときに自動的にこのフィールドに商品数を更新するTriggerを記述していきます。
Triggerの作成は「CREATE TRIGGER トリガ名」で作成します。逆に削除する場合は「DROP TRIGGER トリガ名」で行えます。
Triggerの作成は権限が無いユーザでは作成できないので、管理者(root)で作成しましょう。

それでは、早速下記のように作成してみます。


delimiter //
CREATE TRIGGER category_product_count AFTER INSERT ON product_t 
FOR EACH ROW 
BEGIN 
  UPDATE category_t 
  SET 
         product_count = (SELECT COUNT(*) FROM product_t WHERE category_id = NEW.category_id) 
  WHERE id = NEW.category_id;
END;//
delimiter ;


正しく登録できたかは「show triggers;」とコマンドで確認できます


上記のTriggerの意味は、
product_tテーブルにINSERTされた後にBEGINからENDまでの処理を行うという意味になります。
BEGINからENDまでの処理は登録した商品のカテゴリIDを使用して、category_tテーブルのproduct_countにカテゴリに属する商品数を更新するSQLです。
「NEW.category_id」は登録した商品のカテゴリIDになります。
ちなみに「OLD.category_id」で更新前のカテゴリIDを参照できます。

注意点としては、トリガ内で指定できる使用できる構文にはいろいろな制約があります。
LOCK TABLEやアクションを起こしたテーブルへの更新・追加・削除処理(ここの例だとproduct_t)が行えません。
詳しくは下記に記述されていますので、そちらを参照ください。
http://dev.mysql.com/doc/refman/5.1/ja/routine-restrictions.html

それでは実際に、insert文を発行して確認しましょう。
まずはカテゴリデータをいくつか準備します。


INSERT INTO category_t VALUES('1','category_name1',0);
INSERT INTO category_t VALUES('2','category_name2',0);
INSERT INTO category_t VALUES('3','category_name3',0);


次に商品を登録していきます。
Triggerの処理で商品を登録すると商品に属したカテゴリのproduct_countが更新されるはずです。


INSERT INTO product_t VALUES('1','1','product_name1');
INSERT INTO product_t VALUES('2','1','product_name2');
INSERT INTO product_t VALUES('3','2','product_name3');
INSERT INTO product_t VALUES('4','3','product_name4');
INSERT INTO product_t VALUES('5','1','product_name5');


category_tテーブルを確認するとカテゴリごとの登録されている商品数が更新されていますね。


このようにしてTriggerを作成していきます。
Triggerを使用する点の注意ですが、SQLの負荷を考えて作成を行わないと
パフォーマンスが落ちる場合もあります。
例えばキーにインデックスを張らずに大量のデータから検索した結果を更新するときなどです。
そのようなことを考慮して使用する分にはTriggerの機能をフルに生かせるのではないでしょうか。
皆さんもこの機会に是非、Triggerを使ってみてください。


■オマケ
こんな感じでプログラムっぽくIF文でSQLの処理を分けることもできます。
商品を更新したときに件数を調べて0件じゃないときと0のときで処理を分けてみました。
更新前のカテゴリIDの商品数と更新後のカテゴリIDの商品数を更新するTriggerです。
 ※IF文をかかなくても書けますが、ご愛嬌で。。


delimiter //
CREATE TRIGGER category_product_count_clear AFTER UPDATE ON product_t 
FOR EACH ROW 
BEGIN 
  IF (SELECT COUNT(*) FROM product_t WHERE category_id = OLD.category_id) != 0 THEN
    UPDATE category_t 
    SET 
           product_count = (SELECT COUNT(*) FROM product_t WHERE category_id = OLD.category_id) 
    WHERE id = OLD.category_id;
  ELSE
    UPDATE category_t 
    SET 
           product_count = 0 
    WHERE id = OLD.category_id;
  END IF;

  UPDATE category_t 
  SET  
        product_count = (SELECT COUNT(*) FROM product_t WHERE category_id = NEW.category_id) 
  WHERE id = NEW.category_id;

END;//
delimiter ;


■実行SQL
UPDATE product_t SET category_id='2' WHERE id = '5';

結果