6

次のようなINSERTステートメントがあります。

INSERT INTO officer (officer_number,
                     name,
                     bank_id)    
VALUES ('',
        '',
        8)

ON DUPLICATE KEY UPDATE officer_number = '',
                        name = '',
                        bank_id = 8,
                        id = LAST_INSERT_ID(id)

このやり方でうまくいきました。次のトリガーを追加すると、動作しなくなりました。

CREATE TRIGGER officer_update BEFORE UPDATE ON `officer`
FOR EACH ROW SET NEW.updated_at = NOW(), NEW.created_at = OLD.created_at

officerレコードが挿入されていないわけではありません。引き金はハイジャックLAST_INSERT_ID()か何かのようです。私がこれを言うのは、実行される次のクエリがこれだからです:

INSERT INTO account (import_id,
                     branch_id,
                     account_number,
                     officer_id,
                     customer_id,
                     open_date,
                     maturity_date,
                     interest_rate,
                     balance,
                     opening_balance)
VALUES ('123',
        '4567',
        '789',
        '0', # This is the officer id which is of course invalid
        '321',
        '1992-04-22',
        '2012-05-22',
        '0.0123',
        '0',
        '10000')

まったく同じファイルで何十回もインポートを成功させたので、コードを変更していません。このトリガーを追加した後、インポートが機能しなくなりました。トリガーが原因であると推測する必要があります。別のテーブルで同様の状況が発生し、トリガーを削除すると問題が解決しました。

だから私の質問は:

  1. 具体的には、役員 ID が 0 に設定される原因を誰か説明できますか?
  2. この問題の良い解決策は何ですか?

別のトリガーofficer.created_at(および他の多くのテーブル) があり、トリガーが on であるがoncreated_atであるという厄介な解決策を避けたいと思います。何らかの理由で、MySQL はテーブルごとに 1 つの自動タイムスタンプしか許可しないため、 との両方を行うことはできません。created_atDEFAULT CURRENT_TIMESTAMPupdated_atCURRENT_TIMESTAMPcreated_atupdated_at

は次のとおりSHOW CREATE TABLEです。officer

CREATE TABLE `officer` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `officer_number` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `bank_id` bigint(20) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `officer_number` (`officer_number`,`name`),
  UNIQUE KEY `officer_number_2` (`officer_number`,`bank_id`),
  KEY `bank_id` (`bank_id`),
  CONSTRAINT `officer_ibfk_1` FOREIGN KEY (`bank_id`) REFERENCES `bank` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=102735 DEFAULT CHARSET=latin1
4

2 に答える 2

4

既に存在する場合、エラーを防ぐ方法INSERT ... ON DUPLICATE KEY UPDATEのようです。officer_number(TRIGGER を起動するために) 更新を行う必要がありますか、それとも代わりに使用できますINSERT IGNOREか?:

INSERT IGNORE INTO officer (officer_number,
                     name,
                     bank_id)    
VALUES ('',
        '',
        8);

すでに存在する場合、それは単に何もしないofficer_idため、更新の必要性がなくなります (したがってLAST_INSERT_ID()) 完全に。

それが不可能な場合は、おそらくINSERT ... ON DUPLICATE KEY UPDATE微調整することができます。次の目的がはっきりしません。

id = LAST_INSERT_ID(id)

LAST_INSERT_ID()(引数なし) は、最後に実行された INSERT ステートメントによって AUTO_INCREMENT 列に設定され、そのような列に影響を与える最初の自動生成値を返します。

ただし、引数を指定すると、その引数の値が返され、LAST_INSERT_ID()(引数なしで) を次に呼び出すと、同じ値が返されます。例えば:

SELECT LAST_INSERT_ID(100);
+---------------------+
| LAST_INSERT_ID(100) |
+---------------------+
|                 100 |
+---------------------+

SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|              100 |
+------------------+

したがって、 と仮定するとid == 100、次のようになります。

SELECT LAST_INSERT_ID(id);
+--------------------+
| LAST_INSERT_ID(id) |
+--------------------+
|                100 |
+--------------------+

SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|              100 |
+------------------+

それに続いて:

id = LAST_INSERT_ID(id)

次と同じである必要があります。

id = id

または、Josh Davis が示唆しているように、まったく必要ないはずです。簡単に試しましたid = idか?除外すると具体的にどうなりますか?

マニュアルには次のように記載されています。

ただし、LAST_INSERT_ID() と LAST_INSERT_ID(expr) への参照を混在させた場合の効果は未定義です。

と:

生成された ID は、 接続ごとにサーバーに保持されます。これは、関数によって特定のクライアントに返される値が、そのクライアントによってAUTO_INCREMENT 列に影響を与える最新のステートメントに対して生成された最初の AUTO_INCREMENT 値であることを意味します。この値は、他のクライアントが独自の AUTO_INCREMENT 値を生成したとしても、影響を受けることはありません。

と の両方を使用しているLAST_INSERT_ID()ためLAST_INSERT_ID(expr)、動作は未定義です。さらに、TRIGGER は 1 つの接続 (サーバー上で直接実行される) と見なされる場合がありますが、INSERT ステートメントと CREATE ステートメントは別の接続から呼び出される可能性があります。これと、バージョン間の LAST_INSERT_ID に関連して報告されたさまざまな変更とバグを考えると、あなたのアプローチには問題がある可能性があります。

Josh Davis が言ったことに戻ると、id = LAST_INSERT_ID(id)INSERT ステートメントでの使用を解決したいと思います。officer_idまた、ステートメントでをどのように導出するかを知ることも役立ちます。INSERT INTO accountつまり、ゼロ値を受け取っているものです。

于 2010-12-06T11:08:24.223 に答える
0

を更新しようとする理由がわかりませんid。への呼び出しを削除することはできませんLAST_INSERT_ID()か?

INSERT INTO officer (officer_number,
                     name,
                     bank_id)
VALUES ('',
        '',
        8)

ON DUPLICATE KEY UPDATE officer_number = '',
                        name = '',
                        bank_id = 8

LAST_INSERT_ID()また、過去に動作にいくつかの変更があったため、MySQL のバージョン (および使用したエンジン) を投稿する必要があります。

于 2010-11-16T10:32:42.673 に答える