183

我四处寻找,但没有找到是否可能。

我有这个 MySQL 查询:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8)

字段 id 有一个“唯一索引”,所以不能有两个。现在,如果数据库中已经存在相同的 id,我想更新它。但是我真的必须再次指定所有这些字段,例如:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY UPDATE a=2,b=3,c=4,d=5,e=6,f=7,g=8

或者:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY UPDATE a=VALUES(a),b=VALUES(b),c=VALUES(c),d=VALUES(d),e=VALUES(e),f=VALUES(f),g=VALUES(g)

我已经在插入中指定了所有内容......

额外说明一下,我想使用解决方法来获取 ID!

id=LAST_INSERT_ID(id)

我希望有人能告诉我最有效的方法是什么。

4

9 回答 9

97

给出该UPDATE语句以便可以将旧字段更新为新值。如果您的旧值与新值相同,为什么无论如何都需要更新它?

例如。如果您的列已设置a为;没有必要重新更新它。g28

或者,您可以使用:

INSERT INTO table (id,a,b,c,d,e,f,g)
VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY
    UPDATE a=a, b=b, c=c, d=d, e=e, f=f, g=g;

idLAST_INSERT_ID; _ 您需要指定您正在使用的后端应用程序。

对于 LuaSQL,aconn:getlastautoid()获取值。

于 2013-01-17T16:26:58.667 回答
48

有一个 MySQL 特定的 SQL 扩展,可能是您想要的 -REPLACE INTO

但是它与“ON DUPLICATE UPDATE”的工作方式不同

  1. 它删除与新行冲突的旧行,然后插入新行。只要表上没有主键就可以了,但是如果有,那么如果任何其他表引用该主键

  2. 你不能引用旧行中的值,所以你不能做相当于

    INSERT INTO mytable (id, a, b, c) values ( 1, 2, 3, 4) 
    ON DUPLICATE KEY UPDATE
    id=1, a=2, b=3, c=c + 1;
    

我想使用解决方法来获取 ID!

这应该可以——只要你的主键是自动递增的,last_insert_id() 就应该有正确的值。

但是,正如我所说,如果您实际上在其他表中使用该主键,REPLACE INTO您可能无法接受,因为它会删除通过唯一键发生冲突的旧行。

在您可以通过以下方式减少一些输入之前,有人建议您:

INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE `a`=VALUES(`a`), `b`=VALUES(`b`), `c`=VALUES(`c`);
于 2013-01-17T16:38:46.120 回答
26

这是您的问题的解决方案:

我试图解决像你这样的问题,我想建议从简单的方面进行测试。

请按照下列步骤操作: 从简单的解决方案中学习。

第 1 步:使用此 SQL 查询创建表模式:

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(30) NOT NULL,
  `password` varchar(32) NOT NULL,
  `status` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `no_duplicate` (`username`,`password`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

带有数据的表 <code>user</code>

步骤 2:使用以下 SQL 查询创建两列的索引以防止重复数据:

ALTER TABLE `user` ADD INDEX no_duplicate (`username`, `password`);

或者,从 GUI 创建两列的索引,如下所示: 从 GUI 创建索引 选择要创建索引的列 表 <code>user</code> 的索引

第 3 步:如果存在则更新,如果不使用则插入以下查询:

INSERT INTO `user`(`username`, `password`) VALUES ('ersks','Nepal') ON DUPLICATE KEY UPDATE `username`='master',`password`='Nepal';

INSERT INTO `user`(`username`, `password`) VALUES ('master','Nepal') ON DUPLICATE KEY UPDATE `username`='ersks',`password`='Nepal';

运行上述查询后的表 <code>user</code>

于 2016-02-03T03:42:01.607 回答
25

没有其他办法,我必须指定两次。首先是插入,其次是更新情况。

于 2013-01-18T11:52:23.880 回答
12

以防万一您能够使用脚本语言来准备 SQL 查询,您可以通过使用SET而不是来重用 field=value 对(a,b,c) VALUES(a,b,c)

PHP的一个例子:

$pairs = "a=$a,b=$b,c=$c";
$query = "INSERT INTO $table SET $pairs ON DUPLICATE KEY UPDATE $pairs";

示例表:

CREATE TABLE IF NOT EXISTS `tester` (
  `a` int(11) NOT NULL,
  `b` varchar(50) NOT NULL,
  `c` text NOT NULL,
  UNIQUE KEY `a` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
于 2016-12-06T17:23:31.580 回答
7

您可能需要考虑使用REPLACE INTO语法,但请注意,在重复 PRIMARY / UNIQUE 键时,它会删除该行并插入一个新行。

您无需重新指定所有字段。但是,您应该考虑可能的性能降低(取决于您的表设计)。

注意事项:

  • 如果您有 AUTO_INCREMENT 主键,它将被赋予一个新主键
  • 索引可能需要更新
于 2015-10-07T11:07:00.490 回答
7

我知道已经晚了,但我希望有人能得到这个答案的帮助

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

你可以在这里阅读下面的教程:

https://mariadb.com/kb/en/library/insert-on-duplicate-key-update/

http://www.mysqltutorial.org/mysql-insert-or-update-on-duplicate-key-update/

于 2019-03-20T07:47:45.740 回答
0

使用MySQL v8.0.19及更高版本,您可以这样做: mysql doc

INSERT INTO mytable(fielda, fieldb, fieldc) 
VALUES("2022-01-01", 97, "hello") 
AS NEW(newfielda, newfieldb, newfieldc) 
ON DUPLICATE KEY UPDATE
fielda=newfielda,
fieldb=newfieldb,
fieldc=newfieldc;


旁注:此外,如果您想要在重复键更新部分中使用条件,那么 MySQL 中会有一个扭曲。如果您将 fielda 更新为第一个参数并将其包含在 fieldb 的 IF 子句中,它将已经更新为新值!将其移至末尾或类似位置。假设 fielda 是示例中的日期,并且您只想在日期比以前更新时更新:

INSERT INTO mytable(fielda, fieldb) 
VALUES("2022-01-01", 97) 
AS NEW(newfielda, newfieldb, newfieldc) 
ON DUPLICATE KEY UPDATE
fielda=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfielda,fielda),
fieldb=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfieldb,fieldb);

在这种情况下由于< ! 您需要将fielda 的更新移到其下方或检查 <= 或 = ...!

INSERT INTO mytable(fielda, fieldb) 
VALUES("2022-01-01", 97) 
AS NEW(newfielda, newfieldb, newfieldc) 
ON DUPLICATE KEY UPDATE
fielda=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfielda,fielda),
fieldb=IF(fielda=STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfieldb,fieldb);

这与使用 = 一样可以正常工作,因为在到达 fieldb 的 if 子句之前 fielda 已经更新为其新值...就个人而言,如果您重新排列语句,我最喜欢 <= 在这种情况下...

于 2022-02-18T14:31:18.340 回答
-9

您可以在这种情况下使用插入忽略,如果它得到重复记录,它将忽略 INSERT IGNORE ... ; -- 没有 ON DUPLICATE KEY

于 2015-07-08T09:44:50.923 回答