1

我创建了这个触发器来更新 seq 列。我必须跟踪表中某些项目的顺序,但前提是责任类别 ID = 1,2。所以我的订购很棘手,因为任何具有责任类别 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 都会重置排序。

4

2 回答 2

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;
$$

那是一个快速的复制/粘贴,但它应该是这样的。

于 2012-07-16T16:00:10.387 回答
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

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

于 2012-07-16T16:00:15.533 回答