mysql触发器在同一个表中

时间:2009-09-30 05:51:41

标签: sql mysql triggers

我正在使用mysql5.1并在update.am之后使用相同的表格对insert和updae编写触发器。 table包含字段.id,itemid,value1 all都是整数..

我的触发器是:

 CREATE DEFINER = 'root'@'%' TRIGGER `trig_same`
  AFTER UPDATE
  ON `vote`
  FOR EACH ROW
BEGIN
  insert into vote values(10,1,100);
END|

...但是当我执行更新命令时出现错误:

SQL Error: Can't update table 'vote' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

2 个答案:

答案 0 :(得分:1)

根据定义,触发器会创建循环引用。它会插入另一行,然后需要再次调用触发器,并插入另一行,这将导致再次调用....

如果SQL没有捕到这个,那么投票表最终将满载这些(10,1,100)个记录,unltil会耗尽数据库或硬盘的空间。

我假设您只希望为每个“正常”记录插入添加一个附加记录。这可以通过修改执行插入本身的逻辑来实现(如果可能的话,在该级别添加第二个INSERT) 编辑 [2011年4月17日]:正如约翰所指出的,以下“装置”会因同样的错误而失败。鉴于相当奇怪的潜在用例,我并不担心修复它......
另一种方法是在INSERT Trigger之后使用一个单独的表;投票表的触发器需要测试(10,1,100)值,并在这种情况下返回(不执行任何操作),否则在另一个表上插入记录;这个其他表将触发器在表'投票'上插入此记录。 (对于一个相对奇怪的用例,我做了很多设计!)

答案 1 :(得分:0)

打破循环引用将需要另一个表,例如:

CREATE TABLE `trigger_semaphore` (
  `id` INTEGER(11) NOT NULL,
  `semaphore` INTEGER(11) DEFAULT NULL,
  `actions` VARCHAR(20) COLLATE utf8_general_ci DEFAULT NULL,
  `random` INTEGER(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
)ENGINE=MyISAM
CHARACTER SET 'latin1' COLLATE 'latin1_swedish_ci';

CREATE DEFINER = 'root'@'localhost' TRIGGER `trigger_semaphore_before_upd_tr`
BEFORE UPDATE ON `trigger_semaphore`
  FOR EACH ROW
BEGIN
DECLARE semaphore int;
   set New.random=RAND()*1000;
   if New.actions='++' then
    set New.semaphore=COALESCE(New.semaphore,0)+1;
   elseif New.actions='--' then
    set semaphore= COALESCE(New.semaphore,0);
    if semaphore<=0 then
      set New.semaphore=semaphore;
    else
     set New.semaphore=semaphore-1;
    end if;
   end if;   
END;

在相互更新的表的触发器中使用trigger_semaphore表 这样:

  update  trigger_semaphore set actions='++' where id=1;

  select semaphore into  _semaphore from   trigger_semaphore where  id=1;

  if _semaphore=1 then

  #   ...... Here goes the code without circular reference.......... 

  end if;

现在在触发器

结束时释放信号量
 update  trigger_semaphore set actions='--' where id=1;  

简而言之,首先设置信号量(1)的表只能执行某些信号 声明。一旦你明白了,你就可以使用一种简单的方法;)