内容来自对 chatgpt 的咨询
前言(INSERT...ON DUPLICATE KEY UPDATE 介绍)
当你在MySQL中插入数据,如果唯一键发生冲突,可以使用 INSERT...ON DUPLICATE KEY UPDATE 语句实现插入和更新操作。其基本语法如下:
INSERT INTO table (col1, col2, ...colN)
VALUES (value1, value2, ...valueN)
ON DUPLICATE KEY UPDATE
col1 = value1, col2 = value2, ...colN = valueN;
这条语句的逻辑是:如果插入的记录与表中现有记录的唯一索引或主键冲突,那么就执行 UPDATE 操作。如果没有冲突,那么就执行 INSERT 操作。
例如,表users有唯一键user_id,现在想插入或更新一条 user_id=1 的记录:
INSERT INTO users (user_id, user_name, user_email)
VALUES (1, 'John', '[email protected]')
ON DUPLICATE KEY UPDATE
user_name='John', user_email = '[email protected]';
在以上的例子中,如果 user_id=1 的这条记录已经存在,在执行此语句后,user_name 和 user_email 会被更新为新的值。如果 user_id=1 的记录不存在,那么这个语句就会新插入一条记录。
注意
在 ON DUPLICATE KEY UPDATE 后面的赋值表达式中,你不能使用 VALUES(col) 获取插入语句中的值,因为它可能被认为是值的字面量而不是列表的值。你应该直接使用要输入的值或者变量。
在 grom 中使用 mysql 的这种语法效果
可以使用GORM的 Exec()
函数,执行自定义的SQL语句来实现MySQL的 INSERT...ON DUPLICATE KEY UPDATE
功能。下面这段代码段会尝试插入users数组中的每个用户,并在发生主键冲突的情况下,更新冲突数据的user_name和user_email字段。需要注意的是,VALUES(user_name), VALUES(user_email)中的VALUES函数能引用到插入时的真实数据,占位符会被替换成真实数据。
users := []User{
{UserID: 1, UserName: "John1", UserEmail: "[email protected]"},
{UserID: 2, UserName: "John2", UserEmail: "[email protected]"},
{UserID: 3, UserName: "John3", UserEmail: "[email protected]"},
}
valueStrings := []string{}
valueArgs := []interface{}{}
// 构造插入语句和冲突时的更新语句
for _, user := range users {
valueStrings = append(valueStrings, "(?, ?, ?)")
valueArgs = append(valueArgs, user.UserID)
valueArgs = append(valueArgs, user.UserName)
valueArgs = append(valueArgs, user.UserEmail)
}
stmt := fmt.Sprintf("INSERT INTO users (user_id, user_name, user_email) VALUES %s"+
"ON DUPLICATE KEY UPDATE user_name=VALUES(user_name), user_email=VALUES(user_email)",
strings.Join(valueStrings, ","))
db.Exec(stmt, valueArgs...)
注意点
-
注意使用这种方法时要确保你对用户的数据有100%的信任,或者已经进行了相应的清理,以防止SQL注入攻击。
-
在执行 SQL 语句之前,需要检查 users 数组是否为空。原因是如果 users 长度为0,则跳过构造和执行 SQL 语句的步骤。如果 users 数组为空,那么在构造 SQL 插入语句的过程中,valueStrings 和 valueArgs 切片都将保持为空。这意味着 stmt 字符串将尝试插入空的值,形如:
INSERT INTO users VALUES ON DUPLICATE KEY UPDATE
,这将导致 SQL 语法错误,因为在 "VALUES" 关键字后并未提供任何数据。