如何将原生关联SQL查询转换为Gorm查询并将结果映射到结构体
你用Exec方法无法获取查询结果的核心原因是,Exec 是Gorm提供给无返回结果集的写操作(增删改、DDL等)的方法,不会处理查询返回的行数据,查询操作需要使用Raw方法执行SQL,配合Scan将结果映射到结构体。
实现步骤
1. 定义结果接收结构体
首先定义和返回字段一一对应的结构体,用gorm:"column:xxx"标签映射SQL查询的列别名:
// 字段类型可根据你的实际表字段类型调整,比如UID为数字则将UserID改为int64,时间字段改为time.Time type UserWinStat struct { FullName string `gorm:"column:Full Name"` UserID string `gorm:"column:User ID"` Country string `gorm:"column:Country"` RegistrationDateTime string `gorm:"column:Registration Date & Time"` WinCount int `gorm:"column:Win Count"` }
注意:结构体字段必须首字母大写(可导出),否则Gorm无法完成反射赋值。
2. 执行查询并映射结果
方案一:直接复用现有SQL(推荐,无需修改已经验证过的SQL逻辑)
var userWinStats []UserWinStat querySQL := ` Select CONCAT(kafka_user_stream.FirstName,' ', kafka_user_stream.LastName) AS "Full Name", kafka_user_stream.UID AS "User ID", kafka_user_stream.CountryCode AS "Country", kafka_user_stream.CreatedAt AS "Registration Date & Time", COUNT(jackpotmessage_stream.UID) AS "Win Count" FROM kafka_user_stream LEFT JOIN jackpotmessage_stream ON jackpotmessage_stream.UID = kafka_user_stream.UID WHERE "Type"='goldenTicketWin' GROUP BY "Full Name", "User ID", "Country", "Registration Date & Time" ORDER BY "Win Count" DESC ` // 使用Raw执行原生查询,Scan将结果映射到结构体切片 err := s.db.Raw(querySQL).Scan(&userWinStats).Error if err != nil { // 自行处理查询错误逻辑 } // 后续直接遍历userWinStats即可拿到所有查询结果
方案二:使用Gorm链式API实现(无需硬写完整SQL)
前提是你已经定义了kafka_user_stream表对应的Gorm模型结构体,示例中假设模型名为KafkaUserStream:
var userWinStats []UserWinStat err := s.db.Model(&KafkaUserStream{}). Select(` CONCAT(kafka_user_stream.FirstName,' ', kafka_user_stream.LastName) AS "Full Name", kafka_user_stream.UID AS "User ID", kafka_user_stream.CountryCode AS "Country", kafka_user_stream.CreatedAt AS "Registration Date & Time", COUNT(jackpotmessage_stream.UID) AS "Win Count" `). Joins("LEFT JOIN jackpotmessage_stream ON jackpotmessage_stream.UID = kafka_user_stream.UID"). Where("Type = ?", "goldenTicketWin"). Group(`"Full Name", "User ID", "Country", "Registration Date & Time"`). Order(`"Win Count" DESC`). Scan(&userWinStats).Error if err != nil { // 自行处理查询错误逻辑 }
注意事项
- 不同数据库的标识符引号规则有差异,如果你使用MySQL,上述SQL里的双引号需要替换为反引号,PostgreSQL、SQLite使用双引号即可
- 若查询结果为空,Scan不会返回错误,只会返回长度为0的切片,需自行判断长度处理空结果场景
- 如果你需要分页查询,可以在链式调用中追加
Offset、Limit方法即可
内容的提问来源于stack exchange,提问作者Haseeb Asjad
相关产品推荐
相关产品推荐

