2010-11-05 238 views
6

我有一個INSERT語句,如下所示:ON DUPLICATE KEY UPDATE在有UPDATE觸發器時不起作用

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(還有很多其他表'created_at s)上有另一個觸發器,我寧願避免某種尷尬的解決方案,我在created_at上有一個觸發器,但在updated_at上有一個DEFAULT CURRENT_TIMESTAMP。出於某種原因,MySQL每個表只允許一個自動時間戳,所以我不能爲created_atupdated_atCURRENT_TIMESTAMP

這是officerSHOW CREATE TABLE

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 
+0

請問您可以發佈'SHOW CREATE TABLE officer'的結果以及哪些查詢工作不正確?您的標題顯示爲'ON DUPLICATE KEY UPDATE',但帖子中沒有此類查詢。 – Quassnoi 2010-11-09 13:36:53

+0

Woops。接得好。我已經更新了這個問題。 – 2010-11-09 13:46:54

+0

你可以粘貼你的代碼,用於*退出* LAST_INSERT_ID()'的值嗎?似乎在我的機器上工作正常MySql 5.1.53 – 2010-12-03 05:03:37

回答

4

您的INSERT ... ON DUPLICATE KEY UPDATE似乎是一種防止錯誤的方法,如果officer_number已經存在。您是否需要更新發生(觸發觸發器),或者你能不能改用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 

或者,如喬什戴維斯所建議的那樣,根本不需要。你試過簡單的id = id?排除它時會發生什麼?

manual指出:

但是,如果你混合引用 LAST_INSERT_ID()和 LAST_INSERT_ID(表達式),效果 不確定

和:

生成的ID是 維護在服務器上 每個連接基礎。這意味着, 由功能恢復 給定客戶的價值是 通過該客戶端影響的 AUTO_INCREMENT列最近的語句生成的第一 AUTO_INCREMENT值。 該值不會受其他 客戶端的影響,即使它們生成自己的AUTO_INCREMENT值爲 。

由於您同時使用LAST_INSERT_ID()LAST_INSERT_ID(expr),因此行爲未定義。此外,TRIGGER可能被認爲是一個連接(它直接在服務器上運行),而INSERT和CREATE語句可能是從不同的連接調用的。鑑於此,以及各種版本中與LAST_INSERT_ID相關的更改和錯誤報告,很可能有是您的方法存在問題。

回到Josh Davis說的話,我傾向於在你的INSERT語句中解決使用id = LAST_INSERT_ID(id)。瞭解如何從INSERT INTO account聲明中得出officer_id也是有幫助的 - 即收到零值的聲明。

+0

下面是我最終做的事情:我使用了'INSERT IGNORE',但是如果我把它放在那裏,'LAST_INSERT_ID()'不會出現。在我的INSERT之後,我只是選擇了任何我剛插入的記錄。它可能不是世界上最簡潔的解決方案,但它的工作原理,我厭倦了它的混亂。 – 2010-12-06 15:21:20

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 

此外,你應該張貼您的MySQL版本(以及所使用的引擎),因爲還有的一些改變過去LAST_INSERT_ID()行爲。

+0

沒有'LAST_INSERT_ID()'它不起作用。我正在使用MySQL 5.1.49和InnoDB。 – 2010-12-02 14:02:45

相關問題