插入 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
之后。
无需列出INSERT
或SELECT
中的列,尽管我同意这可能是更好的做法。
【讨论】:
【参考方案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`);
请注意,请确保首先删除其他行中具有相同 name
和 age
值的所有数据。
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:如果值存在,则对行进行更新,如果值不存在,则插入 [重复]