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(以及许多其他表created_at),我宁愿避免某种尴尬的解决方案,即我有一个触发器created_at但一个DEFAULT CURRENT_TIMESTAMPon updated_at。出于某种原因,MySQL 只允许每个表有一个自动时间戳,所以我不能CURRENT_TIMESTAMP同时为created_atupdated_at.

这是SHOW CREATE TABLEfor 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()andLAST_INSERT_ID(expr)时,行为是未定义的。此外,TRIGGER 可能被视为一个连接(它直接在服务器上运行),而 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

此外,您应该发布您的 MySQL 版本(以及使用的引擎),因为LAST_INSERT_ID()过去的行为发生了一些变化。

于 2010-11-16T10:32:42.673 回答