在执行包含许多行的INSERT语句时,我希望跳过重复的条目,否则会导致失败。经过一番研究,我的选择似乎是使用任何一种:

ON DUPLICATE KEY UPDATE,这意味着在某些代价下进行不必要的更新,或者 INSERT IGNORE暗示着邀请其他类型的失败在未通知的情况下潜入。

我的这些假设对吗?简单地跳过可能导致重复的行并继续到其他行,最好的方法是什么?


当前回答

ON DUPLICATE KEY UPDATE并不是真正的标准。它和REPLACE一样标准。参见SQL MERGE。

实际上,这两个命令都是标准命令的替代语法版本。

其他回答

ON DUPLICATE KEY UPDATE并不是真正的标准。它和REPLACE一样标准。参见SQL MERGE。

实际上,这两个命令都是标准命令的替代语法版本。

如果你想知道这一切意味着什么,下面是所有事情的详细说明:

CREATE TABLE `users_partners` (
  `uid` int(11) NOT NULL DEFAULT '0',
  `pid` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`uid`,`pid`),
  KEY `partner_user` (`pid`,`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

主键基于此快速引用表的两列。主键需要唯一的值。

让我们开始:

INSERT INTO users_partners (uid,pid) VALUES (1,1);
...1 row(s) affected

INSERT INTO users_partners (uid,pid) VALUES (1,1);
...Error Code : 1062
...Duplicate entry '1-1' for key 'PRIMARY'

INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1);
...0 row(s) affected

INSERT INTO users_partners (uid,pid) VALUES (1,1) ON DUPLICATE KEY UPDATE uid=uid
...0 row(s) affected

注意,通过将列设置为等于其本身,上面节省了太多额外的工作,实际上不需要更新

REPLACE INTO users_partners (uid,pid) VALUES (1,1)
...2 row(s) affected

现在是多行测试:

INSERT INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...Error Code : 1062
...Duplicate entry '1-1' for key 'PRIMARY'

INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...3 row(s) affected

在控制台中没有生成其他消息,现在在表数据中有这4个值。我删除了除(1,1)之外的所有内容,这样我就可以在相同的场地进行测试

INSERT INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4) ON DUPLICATE KEY UPDATE uid=uid
...3 row(s) affected

REPLACE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...5 row(s) affected

结果出来了。由于这一切都是在一个几乎没有数据的新表上执行的,而且不在生产环境中,因此执行的时间非常短,而且不相关。任何拥有真实数据的人都非常欢迎贡献这些数据。

除此之外。如果在同一个语句中同时使用INSERT IGNORE和ON DUPLICATE KEY UPDATE,如果插入发现重复的键,更新仍然会发生。换句话说,更新优先于忽略。但是,如果ON DUPLICATE KEY UPDATE子句本身导致重复键错误,则该错误将被忽略。

如果您有多个唯一键,或者您的更新试图违反外键约束,就会发生这种情况。

CREATE TABLE test 
 (id BIGINT (20) UNSIGNED AUTO_INCREMENT, 
  str VARCHAR(20), 
  PRIMARY KEY(id), 
  UNIQUE(str));

INSERT INTO test (str) VALUES('A'),('B');

/* duplicate key error caused not by the insert, 
but by the update: */
INSERT INTO test (str) VALUES('B') 
 ON DUPLICATE KEY UPDATE str='A'; 

/* duplicate key error is suppressed */
INSERT IGNORE INTO test (str) VALUES('B') 
 ON DUPLICATE KEY UPDATE str='A';

插入忽略的潜在危险。 如果您试图插入VARCHAR值的时间比列定义的时间长-即使启用了严格模式,该值也会被截断并插入。

如果要在表中插入与之冲突的主键或唯一索引,它将更新冲突的行,而不是插入该行。

语法:

insert into table1 set column1 = a, column2 = b on duplicate update column2 = c;

现在在这里,这个插入语句看起来可能与您之前看到的不同。此插入语句试图将table1中值为a和b的行分别插入列columnn1和column2。

让我们深入理解这句话:

例如:这里的column1被定义为table1中的主键。

现在,如果在table1中,column n1中没有值为“a”的行。因此,这条语句将在table1中插入一行。

现在,如果在table1中,在column2中有一行值为“a”。因此,这条语句将用“c”更新行column2的值,其中columnn1的值为“a”。

因此,如果你想插入一个新行,否则更新该行冲突的主键或唯一索引。 在这个链接上阅读更多