1

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ごとに順序がリセットされます。

4

2 に答える 2

1

回避策は、これをbeforeトリガーにして、挿入前に挿入されているレコード自体を更新することだと思います。

それで

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 FOREACHROWトリガーではこれを行うことはできません。

トリガーの使用には、パフォーマンスと同時実行性に関する懸念がいくつかあります。(同時挿入が実行されているときに列の「重複」値が生成されないという保証はありません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 に答える