2012-07-16 76 views
1

我已创建此触发器来更新seq列。我必须跟踪表中某些项目的顺序,但只有在liability_category_id = 1,2时才有效。所以我的订单很棘手,因为任何带有liability_category_id = 3的项目我都不需要跟踪。创建触发器以更新排序/排序列

在了扳机,我查询找到最后输入的序列号(使用MAX(SEQ)),然后转身和更新与SEQ + 1

DELIMITER $$ 

USE `analysisdb`$$ 

DROP TRIGGER /*!50032 IF EXISTS */ `trigger_liability_detail_after_insert`$$ 

CREATE 
/*!50017 DEFINER = 'admin'@'%' */ 
TRIGGER `trigger_liability_detail_after_insert` AFTER INSERT ON `liability_detail` 
    FOR EACH ROW BEGIN 
    DECLARE SortOrder INT; 
    IF NEW.liability_category_id = 1 OR NEW.liability_category_id = 2 THEN 

    SET SortOrder = (SELECT MAX(seq) FROM liability_detail WHERE analysis_id = new.analysis_id AND liability_category_id IN (1, 2)); 
    UPDATE liability_detail SET seq = (SortOrder + 1) WHERE id = NEW.id; 
    END IF; 
    END; 
$$ 

DELIMITER ; 

新条目然而,当输入一个新的项目时,我得到这个错误:无法更新存储的函数/触发器中的表'liability_detail',因为它已经被调用此存储的函数/触发器的语句使用。

有没有更好的方法来控制这些项目的顺序?我最初的想法是简单地设置第一个seq = 1,然后seq = 2等等。但是,对于每个新的analysis_id,排序都会重置。

+0

以这种方式更新列可能会导致具有相同seq值的多个行,因为最大值可能在插入期间读取,但在另一个插入期间再次读取之前未更新。你应该使用自动增量来处理这个问题。 – 2012-07-16 17:23:42

回答

1

我认为解决方法是在插入之前使其成为一个触发前并更新正在插入的记录。

所以

CREATE 
/*!50017 DEFINER = 'admin'@'%' */ 
TRIGGER `trigger_liability_detail_after_insert` BEFORE INSERT ON `liability_detail` 
    FOR EACH ROW BEGIN 
    DECLARE SortOrder INT; 
    IF NEW.liability_category_id = 1 OR NEW.liability_category_id = 2 THEN 

    SET NEW.seq = 1 + IFNULL((SELECT MAX(seq) FROM liability_detail WHERE analysis_id = new.analysis_id AND liability_category_id IN (1, 2)), 0); 
    END IF; 
    END; 
$$ 

这是一个快速的复制/粘贴,但它应该是类似的规定。

1

这将是棘手的处理。

最简单的答案是,如果这可以被更改为BEFORE INSERT FOR EACH ROW触发, ,那么你可以:

SET NEW.seq = (SortOrder + 1); 

到以前被插入到表中设置该行的值。但是你不能在AFTER INSERT FOR EACH ROW触发器中这样做。

使用触发器有一些性能和并发性问题。 (您没有任何保证,当并发插入正在运行时,您不会为seq列生成“重复”值;但这可能不是您的显示停止问题。)

我宁愿为整个表使用简单的AUTO_INCREMENT列的方法。

从该值将是“按顺序”的所有行,所以像

... WHERE liability_category_id = 1 ORDER BY seq 

查询会“提交订单”的行插入返回行。对于给定的liability_category_id,序列号中将存在“空位”,但插入的序列(顺序)将被保留。 (注意:MyISAM具有AUTO_INCREMENT列的漂亮功能,让我们为索引中的前导列的不同值“分别增加”,但这只适用于MyISAM引擎,它不适用于InnoDB )

除了AUTO_INCREMENT列之外,我还会考虑一个TIMESTAMP DEFAULT CURRENT_TIMESTAMP列来记录插入行时的日期/时间。

... WHERE liability_category_id = 1 ORDER BY timestamp_default_current ASC 

这两种方法都是简单的列定义,不需要编写或维护任何过程代码。