插入 MySQL 表或更新(如果存在)

Posted

技术标签:

【中文标题】插入 MySQL 表或更新(如果存在)【英文标题】:Insert into a MySQL table or update if exists 【发布时间】:2021-08-12 05:25:07 【问题描述】:

我想向数据库表中添加一行,但如果存在具有相同唯一键的行,我想更新该行。

例如:

INSERT INTO table_name (ID, NAME, AGE) VALUES(1, "A", 19);

假设唯一键是ID,在我的数据库中,有一行ID = 1。在这种情况下,我想用这些值更新该行。通常这会报错。 如果我使用INSERT IGNORE,它会忽略错误,但仍然不会更新。

【问题讨论】:

SQL 需要此用例的官方语法,该语法不会强制语法中的值重复并保留主键。 要获取受影响的id,请参考mysql ON DUPLICATE KEY - last insert id? 警告: 从 5.7 版开始,此方法不直接支持将 WHERE 子句作为 INSERT/UPDATE 操作的一部分。此外,UPDATE 实际上算作两个单独的操作(DELETE 和 INSERT)......如果这对审计目的很重要。 (Learnbit) 【参考方案1】:

使用INSERT ... ON DUPLICATE KEY UPDATE

查询:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name="A", age=19

【讨论】:

+1 根据我的发现,这种方法对于自增键和其他唯一键冲突的问题比 REPLACE INTO 的问题少,而且效率更高。 我知道你们都提到了这一点,但我想对其他人说清楚。如果您插入的 ID 不是 PRIMARY KEY 或 UNIQUE,那么这将不起作用。这最初对我不起作用,因为我的 ID 不是唯一的。 这有点晚了,但无论如何:在manual 中声明ON DUPLICATE KEY UPDATE 中的更新会将受影响的行增加 2。如果实际上没有更新,则报告 0(与常规UPDATE)。 另请注意,您可以使用 VALUES (name) 来引用您尝试插入的值,例如INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE name=VALUES(name) , age=VALUES(age)【参考方案2】:

查看替换

http://dev.mysql.com/doc/refman/5.0/en/replace.html

REPLACE into table (id, name, age) values(1, "A", 19)

【讨论】:

@Piontek 因为这个更短更容易理解,没有人解释为什么“插入重复”更好。 它会更改记录的 ID,因此可能会破坏外部引用。 REPLACE INTO 的另一个问题是您必须为所有字段指定值...否则字段将丢失或替换为默认值。 REPLACE INTO 实质上是删除该行(如果存在),并插入新行。在示例中,如果您执行 'REPLACE INTO table (id, age) values (1, 19),则 name 字段将变为 null。 这实际上是删除整行并执行新的INSERT。【参考方案3】:

使用批量插入时,请使用以下语法:

INSERT INTO TABLE (id, name, age) VALUES (1, "A", 19), (2, "B", 17), (3, "C", 22)
ON DUPLICATE KEY UPDATE
    name = VALUES (name),
    ...

【讨论】:

如果VALUES(name)不行,可以试试name = 'name_value',...; VALUES 现在已弃用 - 您应该使用 insert into TABLE (Id, name, age) values (1, "A", 19), (2, "B", 20) 作为重复的 ins密钥更新名称=ins.name,age=ins.age; 所有名称都将更新为相同的值【参考方案4】:

这些解决方案中的任何一个都可以解决您的问题:

INSERT IGNORE INTO table (id, name, age) VALUES (1, "A", 19);

INSERT INTO TABLE (id, name, age) VALUES(1, "A", 19) 
    ON DUPLICATE KEY UPDATE NAME = "A", AGE = 19;  

REPLACE INTO table (id, name, age) VALUES(1, "A", 19);

如果您想详细了解这些声明visit this link

【讨论】:

【参考方案5】:

试试这个:

INSERT INTO table (id, name, age) VALUES (1, 'A', 19) ON DUPLICATE KEY UPDATE id = id + 1;

希望这会有所帮助。

【讨论】:

实际上我不需要将新值添加到具有新 ID 的另一行,而是我想用这个值替换 id = 1 的现有值。 (据我了解,这会增加 id 并添加数据) 我不认为他想在重复时将 id 加一。 “transgress”不是你要找的词 :) 不幸的是,现在我看到了“transgress”,我无法再想象实际的词了..【参考方案6】:

试试这个:

INSERT INTO table (id,name,age) VALUES('1','Mohammad','21') ON DUPLICATE KEY UPDATE name='Mohammad',age='21'

注意: 这里如果 id 是主键,那么在第一次插入 id='1' 之后,每次尝试插入 id='1' 都会更新姓名和年龄,以前的姓名年龄会改变。

【讨论】:

我想在不使用 id 的情况下工作。你试过没有主键吗? @ersks 看到这个问题。用户询问何时有唯一键 我明白了,但我正在尝试解决我的问题,其中只有这些值是已知的。所以,在这种情况下,我写了上面的评论,希望得到正确的解决方案。【参考方案7】:

使用 SQLite 时:

REPLACE into table (id, name, age) values(1, "A", 19)

假设id 是主键。否则它只是插入另一行。请参阅 INSERT (SQLite)。

【讨论】:

replace into 所做的正是“插入或在存在时更新”。 @猫头鹰 +1 ( 1 of 3 ) 我发现这适用于我的情况 - 我需要用唯一键替换现有行,或者如果不存在则添加该行。这里有最简单的解决方案。 ( 2 of 3 ) 我的查询:CREATE TRIGGER worklog_update AFTER INSERT ON worklog FOR EACH ROW REPLACE INTO support_time_monthly_hours ( ProjectID, monthTotalTime, Year, Month ) SELECT jiraissue.PROJECT, SUM(worklog.timeworked), YEAR(CURRENT_DATE()), MONTH(CURRENT_DATE()) FROM worklog, jiraissue WHERE worklog.issueid = jiraissue.ID AND jiraissue.PROJECT = (SELECT PROJECT FROM jiraissue WHERE NEW.issueid = jiraissue.ID ) AND worklog.startdate BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01 00:00:00') AND NOW(); ( 3 of 3 ) 相关问题/答案***.com/questions/41767517/… 在 mysql 中这个问题是如果没有提供其他值,replace 会删除它们。但是@f***o-souza 解决方案更合适【参考方案8】:

只是因为我在这里寻找这个解决方案,但是为了从另一个结构相同的表更新(在我的例子中是网站测试数据库到实时数据库):

INSERT  live-db.table1
SELECT  *
FROM    test-db.table1 t
ON DUPLICATE KEY UPDATE
        ColToUpdate1 = t.ColToUpdate1,
        ColToUpdate2 = t.ColToUpdate2,
        ...

如其他地方所述,只有您要更新的列需要包含在ON DUPLICATE KEY UPDATE 之后。

无需列出INSERTSELECT 中的列,尽管我同意这可能是更好的做法。

【讨论】:

【参考方案9】:

如果您想将non-primary 字段作为ON DUPLICATE 的条件/条件,您可以在该表上创建UNIQUE INDEX 键以触发DUPLICATE

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`);

如果您想组合两个字段以使其在表格中唯一,您可以通过在最后一个参数上添加更多来实现。

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`, `age`);

请注意,请确保首先删除其他行中具有相同 nameage 值的所有数据。

DELETE table FROM table AS a, table AS b WHERE a.id < b.id 
AND a.name <=> b.name AND a.age <=> b.age;

之后,它应该会触发ON DUPLICATE 事件。

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name = VALUES(name), age = VALUES(age)

【讨论】:

我已经尝试过了,我收到一条错误消息,提示“在没有密钥长度的密钥规范中使用了 BLOB/TEXT 列 'column_name'” @Natalia 请创建一个dbfiddle 以便我查看 我会尝试,但基本上,您不能使列的文本类型在 MySQL 中唯一。我把它变成了 varchar。 "DELETE table FROM table AS a, table AS b WHERE a.id b.name AND a.age b.age;"给我错误“MULTI DELETE 中的未知表‘表’”【参考方案10】:

在我的情况下,我创建了下面的查询,但在第一个查询中,如果 id 1 已经存在并且年龄已经存在,那么如果您创建第一个查询而不使用 age,则 age 的值将是 none

REPLACE into table SET `id` = 1, `name` = 'A', `age` = 19

为避免上述问题,请创建如下查询

INSERT INTO table SET `id` = '1', `name` = 'A', `age` = 19 ON DUPLICATE KEY UPDATE `id` = "1", `name` = "A",`age` = 19

希望对你有帮助...

【讨论】:

有谁知道为什么我们必须分配两次值?为什么 MySQL 不允许我们在不复制所有赋值语句的情况下在 ON DUPLICATE KEY UPDATE 处结束查询?一些数据库表有很多列,这似乎是多余的/没有必要的。我理解为什么我们可以选择替代分配,但为什么不能选择省略它们呢?只是好奇是否有人知道。【参考方案11】:

如果您想保留旧字段(例如:姓名)。查询将是:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;

【讨论】:

以上是关于插入 MySQL 表或更新(如果存在)的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:如果值存在,则对行进行更新,如果值不存在,则插入 [重复]

Mysql插入数据:不存在则插入,存在则跳过或更新

oracle表中如果存在就不更新,如果不存在就插入的语句怎么写

如果不存在则插入mysql,如果存在则不更新

MySQL更新如果存在否则插入

MySql 表插入,如果不存在,否则更新