You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GORM执行原生UPDATE查询时遇类型不匹配错误求助

解决PostgreSQL批量更新时的类型不匹配问题

问题分析

你遇到的"update_at" is of type bigint but expression is of type text错误,核心原因是PostgreSQL无法自动推断VALUES子句中update_at字段的正确类型,默认将其识别为text类型,与表中bigint类型的update_at字段不兼容。虽然你怀疑是GORM的写法问题,但本质是原生SQL的类型推断漏洞,GORM的参数处理逻辑也可能放大这个问题。

解决方法

方法1:显式指定VALUES子句中字段的类型

在定义临时表c时,明确声明每个字段的类型,让PostgreSQL直接识别正确类型,避免隐式转换错误:

UPDATE 
  public.openedu_user_tokens AS t 
SET 
  update_at = c.update_at, 
  delete_at = c.delete_at, 
  user_id = c.user_id, 
  org_id = c.org_id, 
  email = c.email, 
  token = c.token, 
  event = c.event, 
  expiry_time = c.expiry_time, 
  send_email = c.send_email, 
  verify_date = c.verify_date, 
  redirect_url = c.redirect_url 
FROM 
  (
    VALUES 
      (
        $1::bigint, $2::bigint, $3::bigint, $4::bigint, $5::bigint, $6::text, $7::text, $8::text, 
        $9::timestamp, $10::boolean, $11::timestamp, $12::text
      ), 
      (
        $13::bigint, $14::bigint, $15::bigint, $16::bigint, $17::bigint, $18::text, $19::text, $20::text, 
        $21::timestamp, $22::boolean, $23::timestamp, $24::text
      )
  ) AS c(
    id bigint, update_at bigint, delete_at bigint, user_id bigint, 
    org_id bigint, email text, token text, event text, expiry_time timestamp, 
    send_email boolean, verify_date timestamp, redirect_url text
  ) 
WHERE 
  t.id = c.id;

注意:需根据你的表字段实际类型调整类型声明,比如如果update_at是timestamp类型,就改成$2::timestamp,确保与表字段类型完全一致。

方法2:用GORM的原生SQL执行时正确传递参数

使用GORM的Exec方法执行原生SQL,确保参数按顺序正确传递,避免GORM对SQL结构进行不必要改写:

sql := `UPDATE 
  public.openedu_user_tokens AS t 
SET 
  update_at = c.update_at, 
  delete_at = c.delete_at, 
  user_id = c.user_id, 
  org_id = c.org_id, 
  email = c.email, 
  token = c.token, 
  event = c.event, 
  expiry_time = c.expiry_time, 
  send_email = c.send_email, 
  verify_date = c.verify_date, 
  redirect_url = c.redirect_url 
FROM 
  (
    VALUES 
      ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12), 
      ($13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24)
  ) AS c(
    id, update_at, delete_at, user_id, 
    org_id, email, token, event, expiry_time, 
    send_email, verify_date, redirect_url
  ) 
WHERE 
  t.id = c.id`

// 按顺序传递所有参数,确保参数类型与表字段匹配
result := db.Exec(sql, param1, param2, param3, ..., param24)

这种方式下GORM仅替换占位符,不会修改SQL结构,只要参数类型正确,就能避免类型不匹配问题。

方法3:使用GORM内置的批量更新API

如果不想手写原生SQL,可以用GORM的批量更新功能,让框架自动生成正确的SQL:

// 定义要更新的记录切片
tokens := []OpeneduUserToken{
  {ID: 1, UpdateAt: 1690000000, DeleteAt: 0, UserID: 100, ...},
  {ID: 2, UpdateAt: 1690001000, DeleteAt: 0, UserID: 101, ...},
}

// 批量更新,GORM会生成高效的批量更新语句
db.Model(&OpeneduUserToken{}).Updates(tokens)

这种方式完全规避了手写原生SQL的类型问题,GORM会根据模型定义自动处理字段类型和SQL生成。

内容的提问来源于stack exchange,提问作者Anoencs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 11:33:15