创建触发器以更新排序/订单列

时间:2012-07-16 15:43:45

标签: mysql function triggers insert

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

在我的触发器中,我查询找到最后输入的seq编号(使用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重置了排序。

2 个答案:

答案 0 :(得分: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 :(得分: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

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