Go GORM中Update from SubQuery更新失效及变量报错问题
问题场景
你需要实现如下MySQL多表更新逻辑,完成跨表数据匹配写入:
update goods t1, user t2 set t1.user_id = t2.user_id where t1.phone = ? and t2.phone = ?
尝试用GORM的Update from SubQuery能力实现时遇到两个问题:
- 编写的子查询代码运行不符合预期,日志打印最终执行SQL为
UPDATE good SET user_id = 0,没有带上匹配条件和子查询逻辑 - 提前声明两张表的模型实例
var users models.User、var goods models.Good时,会触发users and goods declared but not used的编译错误
错误原因
- 更新目标指定错误:要更新的是
goods表的数据,原写法Model(&models.User{})把更新目标设成了用户表,框架生成SQL时完全偏离预期 - 子查询绑定逻辑错误:原写法没有把构建好的子查询作为
Update方法的赋值参数传入,框架拿不到子查询结果,就给字段赋了int类型的零值0 - 无意义的变量声明:Go语言编译阶段会检查所有声明的变量是否被引用,只声明模型变量但不实际使用,必然触发未使用变量的编译报错,这类无意义声明不需要保留。
正确实现方案
方案1:GORM原生子查询写法(推荐)
不需要额外声明无用的模型变量,直接按GORM子查询更新的标准链式写法调用即可:
// 构建子查询:匹配手机号查询对应用户的user_id userSubQuery := models.DB.Model(&models.User{}).Select("user_id").Where("phone = ?", row[3]) // 对goods表执行更新,匹配对应手机号的商品行,把user_id设置为子查询的返回结果 err := models.DB.Model(&models.Good{}). Update("user_id", userSubQuery). Where("phone = ?", row[3]). Error // 按需处理返回的err
生成的SQL和你预期的多表更新逻辑完全等价,执行效率和原生SQL一致。
方案2:直接执行原生SQL(最稳妥,无框架语法兼容问题)
如果不想记忆GORM的子查询语法规则,直接用Exec方法写原生SQL即可,完全可控:
err := models.DB.Exec(` UPDATE goods t1, user t2 SET t1.user_id = t2.user_id WHERE t1.phone = ? AND t2.phone = ? `, row[3], row[3]).Error // 按需处理返回的err
- 注意:两种写法都不需要提前声明未使用的模型变量,直接在方法参数里传入模型指针引用即可,不会触发编译错误。
内容的提问来源于stack exchange,提问作者Elsa
相关产品推荐
相关产品推荐

