2009-07-31 8 views
15

の値にフィールドを更新するために、私は3つの列で一つのテーブルを持って言う:主idキー、group_id int、value varchar。私はそのようなgroup_idに挿入するとMySQLのトリガーは、私が挿入されたレコードに対して次の操作を実行するトリガーを持っていると思いID

INSERT INTO table(value, group_id) VALUES ('a', 10) 

私が持っているしたいと思います:

id | group_id | value 
---+----------+------ 
1 |  10 | a 

が、私はgroup_idを省略:

INSERT INTO table(value) VALUES ('b') 

それが自動的にする必要がありますこのレコードのidに設定します。

id | group_id | value 
---+----------+------ 
2 |  2 | b 

トリガーでも可能ですか? (私は挿入するが、トリガーが立派になりた後にレコードを更新することができます知っている。)

答えて

25

トリガーを使用しても、1つのステートメントでこれを行う方法はわかりません。 @Luckyが提案

トリガー溶液は、MySQLには次のようになります。

CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable 
FOR EACH ROW BEGIN 
    SET NEW.group_id = COALESCE(NEW.group_id, NEW.id); 
END 

しかし、問題があります。 BEFORE INSERTフェーズでは、自動生成されたid値はまだ生成されていません。だから、group_idがnullの場合、常に0

それNEW.idデフォルトである。しかし、あなたはNEW.idの生成された値へのアクセス権を持っているので、AFTER INSERT相中に発射し、このトリガーを変更する場合は、列の値を変更することはできません。

MySQLは、列のの式をサポートしていないため、この動作もテーブル定義で宣言することはできません。

唯一の解決策は、INSERTを実行してから、すぐにUPDATEを実行して、group_idが設定されていない場合は変更します。

INSERT INTO MyTable (group_id, value) VALUES (NULL, 'a'); 
UPDATE MyTable SET group_id = COALESCE(group_id, id) WHERE id = LAST_INSERT_ID(); 
+0

を試してみよう。 2016 –

+0

@AA_PVであっても、これはOracleのように独立したシーケンスオブジェクトによって解決できます。これは、2003年からMySQLで公開されている機能リクエストです:https://bugs.mysql.com/bug.php?id=1625しかし、Oracleでは、シーケンスを使用するためには、アプリケーションコードで呼び出す必要があります。自動インクルード主キーを持つテーブルに*すべての* INSERTのコードを記述することを意味します。あるいは、*そのようなテーブルごとにトリガーを書く。 MySQLユーザは非常に多くのトリガをスキップすることができ、単にカラムオプションとして 'AUTO_INCREMENT'を宣言するのが好きです。 –

+0

MySQLでは2つのAUTO_INCREMENTカラムは使用できません。私はhttp://stackoverflow.com/a/7345183/4411645に似た何かができると思うが。また、ネストされたクエリを避けるために、おそらくそれはアプリケーションコードでも維持できますが、それはさらに安全ではないかもしれません。 –

0

私はこれがあなた

のために働くだろうと信じている私は2つのテーブル

test_b: a_id, value 
test_c: a_id, value 

を持っており、ここではAですテスト挿入のトリガーb。それはA_IDがnullであるかどうかをチェックし、それがある場合、それはあなたが求めて何をすべき0

CREATE TRIGGER test_b AFTER INSERT ON test_b 
    FOR EACH ROW 
    INSERT INTO test_c (a_id, value) VALUES (IFNULL(NEW.a_id, 0),NEW.value) 
+0

テーブルの構造について詳しく知っていれば、私はあなたのためにこのクエリを変更することができます。 –

-2

このトリガを挿入します。

CREATE TRIGGER mytrigger BEFORE INSERT ON mytable 
      IF new.group_id IS NULL 
      SET new.group_id = new.id 
      END IF 
     END; 

それはMYSQL documentationページでは非常に同様の例からコピーされています。

+0

MySQLで動作しません: SQL構文に誤りがあります。あなたのMySQLサーバのバージョンに対応するマニュアルをチェックして、正しい構文が1行目の「WHERE new.group_id IS NULL END」の近くで使用するようにしてください。 – szeryf

+0

http://dev.mysqlの例から正確な構文を得ることができます。 .com/doc/refman/5.1/ja/create-trigger.html - 私はテストしませんでした。私は編集 – Lucky

-2

この状況では、トリガーは過度のようです。単にデフォルトを適用するだけです。私はここで答えています

CREATE TABLE `test` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `value` varchar(100) NOT NULL, 
    `group_id` TINYINT(3) UNSIGNED NOT NULL DEFAULT '2' 
) 
+0

申し訳ありませんが、その点を見逃しました。リテラル値 '2'を' group_id'として挿入することではありません。 'group_id'を明示的に指定しない限り、このレコードの' id'を 'group_id'としたいと思います。 – szeryf

0

は、Bill Karwin状態受け入れ答えのように:BEFORE INSERTの段階では

、自動生成されたid値は はまだ生成されていません。 :ここでは、OPのための(と来る観光客)いくつかのポイントです - group_idのがnullであれば、常に0


あるNEW.idがデフォルトでは、私はそれのための答えを持っています

Error Code: 1442 
Can't update table 'MyTable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. 

1.to新しい行を更新し 使用:それはあなたがエラー1442を買ってあげるためにあなたは、トリガーが呼び出された場所からテーブルを更新することはできませんトリガー、あなたはNEW演算子すなわち介してアクセスすることができ、新しい行のためにすべてのフィールドを、更新することができ、このよう

set NEW.group_id = NEW.id 

2.Get AUTO_INCREMENT値の前に挿入

SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='MyTable' 

合計にSQLのトリガーSQLは、次のようなものになります。

DELIMITER // 
DROP TRIGGER IF EXISTS MyTrigger// 
CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable 
FOR EACH ROW BEGIN 
    IF new.group_id IS NULL 
     set @auto_id := (SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES 
         WHERE TABLE_NAME='MyTable' AND TABLE_SCHEMA=DATABASE()); 
     set NEW.group_id = @auto_id; 
    ENF IF; 
END; 
// 
DELIMITER ; 
+0

表からauto_increment値を選択すると、競合状態が発生します。 –

関連する問題