-PR-
解決済み

トリガーについて

  • すぐに回答を!
  • 質問No.8769110
  • 閲覧数146
  • ありがとう数13
  • 気になる数0
  • 回答数3
  • コメント数0

お礼率 85% (739/868)

このジャンルでお願いします。
次のようなテーブルで

DROP TABLE IF EXISTS item;

CREATE TABLE IF NOT EXISTS item (
id int(11) NOT NULL AUTO_INCREMENT,
parent_id INT,
name varchar(32) NOT NULL,
level int NOT NULL,
FOREIGN KEY (parent_id) REFERENCES item(id) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO item (parent_id, name) VALUES (null, 'item1');
INSERT INTO item (parent_id, name) VALUES (1, 'item2');
INSERT INTO item (parent_id, name) VALUES (2, 'item3');
INSERT INTO item (parent_id, name) VALUES (3, 'item4');
INSERT INTO item (parent_id, name) VALUES (2, 'item5');
INSERT INTO item (parent_id, name) VALUES (null, 'item6');
INSERT INTO item (parent_id, name) VALUES (6, 'item7');
INSERT INTO item (parent_id, name) VALUES (null, 'item8');

DROP PROCEDURE IF EXISTS UPDATE_LEVEL;
DELIMITER //
CREATE PROCEDURE UPDATE_LEVEL()
BEGIN
DECLARE CNT INT;
DECLARE LVL INT;
SET LVL=1;
UPDATE item SET level=0;
UPDATE item
SET level=LVL
WHERE parent_id IS NULL;
SELECT COUNT(*) INTO CNT FROM item WHERE level=LVL;
WHILE CNT>0 DO
UPDATE item
INNER JOIN (SELECT id FROM item WHERE level=LVL) as temp ON parent_id=temp.id
SET item.level=LVL+1;
SET LVL=LVL+1;
SELECT COUNT(*) INTO CNT FROM item WHERE level=LVL;
END WHILE;
END
//
DELIMITER ;

DROP TRIGGER IF EXISTS TRG_INSERT_ITEM;
DELIMITER //
CREATE TRIGGER TRG_INSERT_ITEM AFTER INSERT ON item
FOR EACH ROW BEGIN
CALL UPDATE_LEVEL();
END;
//
DELIMITER ;

itemテーブルにinsertした場合にトリガーでUPDATE_LEVEL()を実行するようにしているのですが、
実際に挿入すると、

>Can't update table 'item' in stored function/trigger because it is already used by statment which invoked this stored function/trigger .

このようなエラーが出てしまいます・・・
UPDATE_LEVEL()にinsertらしき記述はないと思うのですが、
これはなぜこのようなエラーが出るのでしょうか?
通報する
  • 回答数3
  • 気になる
    質問をブックマークします。
    マイページでまとめて確認できます。

質問者が選んだベストアンサー

  • 回答No.2
レベル14

ベストアンサー率 51% (3827/7415)

あ、ごめんなさい
itemテーブルにデータをつっこんだときに
itemテーブル自信をアップデートするということですか?

http://dev.mysql.com/doc/refman/5.1/ja/routine-restrictions.html

その関数やトリガを実行したステートメントが ( 読み取り、または書込みに )
すでに使用しているテーブルを改変することはできない
・・・という制限があります
お礼コメント
takagoo100

お礼率 85% (739/868)

ご回答有難うございます。
なるほど、たしかにそうですね。
ではitemテーブルにデータを挿入した場合は次に
CALL UPDATE_LEVEL();
を呼び出す方法でしか更新する方法ないということなのでしょうか?
なにかこのテーブルに関しても自動的(トリガ的な感じで)に更新するやり方があれば良いのですが。。
投稿日時 - 2014-09-26 22:38:24

その他の回答 (全2件)

  • 回答No.1
レベル14

ベストアンサー率 51% (3827/7415)

外部キー制約とインサートのトリガーが競合していますね
外部キー制約はどうしてもいりますか?
お礼コメント
takagoo100

お礼率 85% (739/868)

ご回答有難うございます。
外部キー制約を次のように

DROP TABLE IF EXISTS item;
CREATE TABLE IF NOT EXISTS item (
id int(11) NOT NULL AUTO_INCREMENT,
parent_id INT,
name varchar(32) NOT NULL,
level int NOT NULL,
PRIMARY KEY(id)
) DEFAULT CHARSET=utf8;

外して試してみたのですが全く同じようなエラーでした・・・
外部キーって当然itemテーブルでのことですよね?
一応、自分としては外部キー制約があればもし削除した場合に
それに関連する行もついでに削除してくれるし、
あとphpmyadminなどを利用して閲覧するときにリンクが貼ってあってそのカラムを辿れるのが便利だなと思って
なんとなく使用しています。
そこら辺も含めて一般的に外部キー制約に対するyambejpさんのお考えがあれば
アドバイス頂けないでしょうか?
投稿日時 - 2014-09-26 17:04:08


  • 回答No.3
レベル14

ベストアンサー率 51% (3827/7415)

無限ループ処理になりそうなので無理だと思います

たしょうタイムラグはでますが
スケジュール管理用のテーブルをひとつ用意して、
コールしたいイベントが発生したときに管理テーブルのフラグをたて
イベントスケジューラでフラグが立っていたらcallしてフラグを消す
・・・的な処理を5分ごとに実行すればある程度目的は達成できるかと

どうしても即座に反映したければ、アプリケーション側でCALLする方が
確実ですが。
お礼コメント
takagoo100

お礼率 85% (739/868)

ご回答有難うございます。
なるほど、たしかにそのやり方だと大変そうですね。。
自分もアプリケーション側で呼び出すしかないのかなぁとは思っています。
とりあえず参考になりました。
ありがとうございます。
投稿日時 - 2014-09-30 12:27:10
このQ&Aのテーマ
このQ&Aで解決しましたか?
AIエージェント「あい」

こんにちは。AIエージェントの「あい」です。
あなたの悩みに、OKWAVE 3,500万件のQ&Aを分析して最適な回答をご提案します。

このQ&Aにこう思った!同じようなことあった!感想や体験を書こう
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。

その他の関連するQ&A、テーマをキーワードで探す

キーワードでQ&A、テーマを検索する
-PR-
-PR-

特集


専門家があなたの悩みに回答!

ピックアップ

ページ先頭へ