2013-03-08 211 views
30

我正在运行MySQL查询。但是,当一个新的行从表单输入添加我得到这个错误:MySql错误:无法更新存储的函数/触发器中的表,因为它已被调用此存储函数/触发器的语句使用

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

从代码:

CREATE TRIGGER `capital` AFTER INSERT ON `brandnames` 
FOR EACH 
ROW UPDATE brandnames 
SET bname = CONCAT(UCASE(LEFT(bname, 1)) , LCASE(SUBSTRING(bname, 2))) 

这个错误是什么意思?

+0

什么是你想用你的触发器做什么?表架构,示例数据和示例INSERT查询将帮助很多 – Steve 2013-03-08 18:22:50

+0

我想将案例更改为enrered行值的大写。所以我希望这个触发器能够在输入一行时自动为我执行此操作。我不想要JavaScript。 – 2013-03-08 18:30:33

+0

@EricLeschinski我不知道他在那个问题上做了什么。 – 2013-03-08 18:32:53

回答

51

而INSERT触发器被解雇你不能改变一个表。 INSERT可能会执行一些可能导致死锁的锁定。另外,从触发器更新表格会导致同一个触发器在无限递归循环中再次触发。这些原因都是MySQL阻止你这样做的原因。

但是,根据您要实现的内容,您可以使用NEW.fieldname或旧值(如果使用OLD进行UPDATE)访问新值。

如果你有一排名为full_brand_name,你想用前两个字母作为一个简短的名字在外地small_name您可以使用:

CREATE TRIGGER `capital` BEFORE INSERT ON `brandnames` 
FOR EACH ROW BEGIN 
    SET NEW.short_name = CONCAT(UCASE(LEFT(NEW.full_name,1)) , LCASE(SUBSTRING(NEW.full_name,2))) 
END 
+1

正如另一个SO问题所引用的(http://stackoverflow.com/questions/1582683/mysql-trigger -stored-trigger-is-already-used-by-statement-which-invoked-stored-t),MySQL不支持这个功能(http://forums.mysql.com/read.php? 99,122354,240978#msg-240978),即使其竞争对手也这么做。 – 2013-06-18 18:46:16

+1

它很有意义@Steve! – 2013-10-09 10:16:38

+0

@Steve我遇到了同样的问题。当我尝试:update employee_audit set lastName ='Sharma'其中employeeNumber = 112; – 2017-07-10 08:43:20

4

正确的语法是:

FOR EACH ROW SET NEW.bname = CONCAT(UCASE(LEFT(NEW.bname, 1)) 
            , LCASE(SUBSTRING(NEW.bname, 2))) 
+0

MySQL说:后续触发不允许更新新行。 :( – 2013-03-08 18:43:06

+1

对不起,您需要将它从AFTER INSERT更改为BEFORE INSERT,如在Steve的答案中 – rsanchez 2013-03-08 18:44:19

+0

It worked :)谢谢 – 2013-03-08 18:56:44

2

我有同样的问题并解决添加“新“。在更新字段之前。我在这里发表充满触发有人想写一个触发器

DELIMITER $$ 

USE `nc`$$ 

CREATE 
    TRIGGER `nhachung_province_count_update` BEFORE UPDATE ON `nhachung` 
    FOR EACH ROW BEGIN 

    DECLARE slug_province VARCHAR(128); 
    DECLARE slug_district VARCHAR(128); 

    IF old.status!=new.status THEN /* neu doi status */ 
     IF new.status="Y" THEN 
      UPDATE province SET `count`=`count`+1 WHERE id = new.district_id; 
     ELSE 
      UPDATE province SET `count`=`count`-1 WHERE id = new.district_id; 
     END IF; 
    ELSEIF old.province_id!=new.province_id THEN /* neu doi province_id + district_id */ 

     UPDATE province SET `count`=`count`+1 WHERE id = new.province_id; /* province_id */ 
     UPDATE province SET `count`=`count`-1 WHERE id = old.province_id; 
     UPDATE province SET `count`=`count`+1 WHERE id = new.district_id; /* district_id */ 
     UPDATE province SET `count`=`count`-1 WHERE id = old.district_id; 

     SET slug_province = (SELECT slug FROM province WHERE id= new.province_id LIMIT 0,1); 
     SET slug_district = (SELECT slug FROM province WHERE id= new.district_id LIMIT 0,1); 
     SET new.prov_dist_url=CONCAT(slug_province, "/", slug_district); 

    ELSEIF old.district_id!=new.district_id THEN 

     UPDATE province SET `count`=`count`+1 WHERE id = new.district_id; 
     UPDATE province SET `count`=`count`-1 WHERE id = old.district_id; 

     SET slug_province = (SELECT slug FROM province WHERE id= new.province_id LIMIT 0,1); 
     SET slug_district = (SELECT slug FROM province WHERE id= new.district_id LIMIT 0,1); 
     SET new.prov_dist_url=CONCAT(slug_province, "/", slug_district); 

    END IF; 


    END; 
$$ 

DELIMITER ; 

希望这有助于有人

1

A“之前,插入” - 触发器是实现对插入相同的表更新的唯一途径,并且只能从MySQL 5.5+开始。但是,自动增量字段的值仅适用于“AFTER-INSERT”触发器 - 它在BEFORE-case中默认为0。因此下面的示例代码将设置基础上,自动递增值id将编译一个预先计算的代理键的值,但实际并不起作用,因为NEW.id将始终为0:

create table products(id int not null auto_increment, surrogatekey varchar(10), description text); 
create trigger trgProductSurrogatekey before insert on product 
for each row set NEW.surrogatekey = 
    (select surrogatekey from surrogatekeys where id = NEW.id); 
相关问题