2012-07-16 40 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 

這兩種方法都是簡單的列定義,不需要編寫或維護任何過程代碼。