使用Gorm执行PostgreSQL原生sum查询时字段值为0的问题
问题描述
我在PostgreSQL中执行以下原生查询:
SELECT at."category" AS "category", at."month" AS "month", sum(at.price_aft_discount) as "sum", sum(at.qty_ordered) as "sum2" FROM all_trans at GROUP BY at."category", at."month" ORDER BY at."category" ASC, at."month" asc
在DBeaver中能得到正确的非零聚合结果,但sum和sum2列显示类型为numeric(131089,0),且提示「无对应表列」。
使用Go语言的Gorm框架查询时,定义了如下结构体:
type ATQueryResult struct { category string `gorm:"column:category"` month string `gorm:"column:month"` sum float32 `gorm:"column:sum"` sum2 float32 `gorm:"column:sum2"` } queryString := ... // 上述SQL语句 var result []ATQueryResult db.Table(model.TableAllTrans).Raw(queryString).Find(&result) fmt.Println(result[3])
执行后所有result[i].sum和result[i].sum2的值均为0,需要解决字段映射异常问题。
问题原因
- 类型不匹配:PostgreSQL的
sum()函数返回numeric类型(聚合大量数据时精度极高),而结构体中使用float32类型,Gorm在类型转换时失败,默认赋值为0。 - (次要)字段名大小写敏感:SQL中别名使用双引号包裹(
"sum"),若PostgreSQL开启标识符大小写敏感,结构体标签中无引号的sum可能无法匹配列名。
解决方案
方案1:使用对应Go类型适配PostgreSQL numeric
PostgreSQL的numeric类型推荐使用github.com/shopspring/decimal库的Decimal类型进行映射,避免精度丢失和转换失败:
- 安装依赖:
go get github.com/shopspring/decimal
- 修改结构体:
import "github.com/shopspring/decimal" type ATQueryResult struct { category string `gorm:"column:category"` month string `gorm:"column:month"` sum decimal.Decimal `gorm:"column:sum"` sum2 decimal.Decimal `gorm:"column:sum2"` }
- 如需转换为float32使用:
sumFloat, _ := result[3].sum.Float32() sum2Float, _ := result[3].sum2.Float32()
方案2:SQL中显式转换为float类型
若确认数据精度不会丢失,可在SQL中将聚合结果直接转为float类型:
SELECT at."category" AS "category", at."month" AS "month", sum(at.price_aft_discount)::float as "sum", sum(at.qty_ordered)::float as "sum2" FROM all_trans at GROUP BY at."category", at."month" ORDER BY at."category" ASC, at."month" asc
修改后结构体中的float32即可正确映射。
方案3:修正字段名映射(针对大小写敏感场景)
若PostgreSQL因双引号导致列名大小写敏感,可修改结构体标签为带引号的形式:
type ATQueryResult struct { category string `gorm:"column:\"category\""` month string `gorm:"column:\"month\""` sum float32 `gorm:"column:\"sum\""` sum2 float32 `gorm:"column:\"sum2\""` }
内容的提问来源于stack exchange,提问作者Mike Abbey
相关产品推荐
相关产品推荐

