查询数据
2026/1/15大约 4 分钟GORMQuerySelect
查询数据
一、基本查询
1.1 查询单条记录
var user User
// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;
// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
// 随机获取一条记录
db.Take(&user)
// SELECT * FROM users LIMIT 1;1.2 根据主键查询
// 主键为整数
db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;
// 主键为字符串
db.First(&user, "id = ?", "1b74413f-f3b8-409f-ac47-e8c062e3472a")
// 查询多个主键
db.Find(&users, []int{1, 2, 3})
// SELECT * FROM users WHERE id IN (1,2,3);1.3 查询所有记录
var users []User
db.Find(&users)
// SELECT * FROM users;二、条件查询
2.1 String 条件
// 单个条件
db.Where("name = ?", "张三").First(&user)
// 多个条件
db.Where("name = ? AND age >= ?", "张三", 18).Find(&users)
// IN 查询
db.Where("name IN ?", []string{"张三", "李四"}).Find(&users)
// LIKE 查询
db.Where("name LIKE ?", "%张%").Find(&users)
// BETWEEN
db.Where("age BETWEEN ? AND ?", 18, 30).Find(&users)2.2 Struct 条件
// 使用结构体(只会查询非零值字段)
db.Where(&User{Name: "张三", Age: 18}).Find(&users)
// SELECT * FROM users WHERE name = "张三" AND age = 18;
// 零值不会被查询
db.Where(&User{Name: "张三", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "张三";2.3 Map 条件
// 使用 Map(可以查询零值)
db.Where(map[string]interface{}{"name": "张三", "age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "张三" AND age = 0;2.4 指定字段查询
// 只查询指定字段
db.Select("name", "age").Find(&users)
// SELECT name, age FROM users;
// 排除字段
db.Omit("password").Find(&users)三、高级查询
3.1 Or 条件
db.Where("name = ?", "张三").Or("name = ?", "李四").Find(&users)
// SELECT * FROM users WHERE name = '张三' OR name = '李四';
// 使用结构体
db.Where("name = ?", "张三").Or(User{Name: "李四"}).Find(&users)3.2 Not 条件
db.Not("name = ?", "张三").Find(&users)
// SELECT * FROM users WHERE NOT name = "张三";
db.Not(map[string]interface{}{"name": []string{"张三", "李四"}}).Find(&users)
// SELECT * FROM users WHERE name NOT IN ("张三", "李四");3.3 排序
// 升序
db.Order("age").Find(&users)
// SELECT * FROM users ORDER BY age;
// 降序
db.Order("age desc").Find(&users)
// 多字段排序
db.Order("age desc, name").Find(&users)3.4 限制和偏移
// Limit
db.Limit(10).Find(&users)
// SELECT * FROM users LIMIT 10;
// Offset
db.Offset(5).Limit(10).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;
// 分页
page := 2
pageSize := 10
db.Offset((page - 1) * pageSize).Limit(pageSize).Find(&users)3.5 分组和聚合
type Result struct {
Age int
Count int
}
var results []Result
db.Model(&User{}).Select("age, count(*) as count").Group("age").Find(&results)
// SELECT age, count(*) as count FROM users GROUP BY age;
// Having
db.Model(&User{}).Select("age, count(*) as count").
Group("age").
Having("count > ?", 10).
Find(&results)3.6 去重
db.Distinct("name").Find(&users)
// SELECT DISTINCT name FROM users;四、Join 查询
4.1 基本 Join
type Result struct {
Name string
Email string
}
var results []Result
db.Model(&User{}).
Select("users.name, emails.email").
Joins("left join emails on emails.user_id = users.id").
Scan(&results)4.2 Join 条件
db.Joins("JOIN emails ON emails.user_id = users.id AND emails.verified = ?", true).
Find(&users)4.3 多表 Join
db.Joins("JOIN profiles ON profiles.user_id = users.id").
Joins("JOIN addresses ON addresses.user_id = users.id").
Find(&users)五、子查询
5.1 Where 子查询
db.Where("amount > (?)", db.Table("orders").Select("AVG(amount)")).
Find(&orders)
// SELECT * FROM orders WHERE amount > (SELECT AVG(amount) FROM orders);5.2 From 子查询
db.Table("(?) as u", db.Model(&User{}).Select("name", "age")).
Where("age > ?", 18).
Find(&users)六、原生 SQL
6.1 Raw SQL
// 查询
db.Raw("SELECT name, age FROM users WHERE name = ?", "张三").Scan(&users)
// 执行
db.Exec("UPDATE users SET age = ? WHERE name = ?", 18, "张三")6.2 命名参数
db.Where("name = @name AND age = @age",
sql.Named("name", "张三"),
sql.Named("age", 18)).
Find(&users)七、扫描结果
7.1 Scan 到结构体
type Result struct {
Name string
Age int
Total int64
}
var result Result
db.Model(&User{}).
Select("name, age, count(*) as total").
Group("name, age").
Scan(&result)7.2 Scan 到 Map
var result map[string]interface{}
db.Model(&User{}).First(&result)
var results []map[string]interface{}
db.Model(&User{}).Find(&results)7.3 Pluck
// 查询单列
var names []string
db.Model(&User{}).Pluck("name", &names)
// SELECT name FROM users;
// 查询多列
var ages []int
db.Model(&User{}).Pluck("age", &ages)八、作用域
8.1 定义作用域
func ActiveUsers(db *gorm.DB) *gorm.DB {
return db.Where("status = ?", 1)
}
func AgeGreaterThan(age int) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return db.Where("age > ?", age)
}
}8.2 使用作用域
// 单个作用域
db.Scopes(ActiveUsers).Find(&users)
// 多个作用域
db.Scopes(ActiveUsers, AgeGreaterThan(18)).Find(&users)8.3 分页作用域
func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
offset := (page - 1) * pageSize
return db.Offset(offset).Limit(pageSize)
}
}
// 使用
db.Scopes(Paginate(1, 10)).Find(&users)九、智能选择字段
9.1 Select 优化
// 只查询需要的字段
db.Select("id", "name").Find(&users)
// 使用结构体
type APIUser struct {
ID uint
Name string
}
db.Model(&User{}).Find(&apiUsers)十、完整示例
10.1 用户列表查询
type UserQuery struct {
Name string
Email string
MinAge int
MaxAge int
Status int
Page int
PageSize int
}
func (s *UserService) List(query UserQuery) ([]User, int64, error) {
var users []User
var total int64
db := s.db.Model(&User{})
// 条件查询
if query.Name != "" {
db = db.Where("name LIKE ?", "%"+query.Name+"%")
}
if query.Email != "" {
db = db.Where("email = ?", query.Email)
}
if query.MinAge > 0 {
db = db.Where("age >= ?", query.MinAge)
}
if query.MaxAge > 0 {
db = db.Where("age <= ?", query.MaxAge)
}
if query.Status > 0 {
db = db.Where("status = ?", query.Status)
}
// 统计总数
db.Count(&total)
// 分页查询
offset := (query.Page - 1) * query.PageSize
err := db.Offset(offset).Limit(query.PageSize).
Order("created_at desc").
Find(&users).Error
return users, total, err
}10.2 统计查询
type UserStats struct {
TotalUsers int64
ActiveUsers int64
AverageAge float64
NewUsersToday int64
}
func (s *UserService) GetStats() (*UserStats, error) {
var stats UserStats
// 总用户数
s.db.Model(&User{}).Count(&stats.TotalUsers)
// 活跃用户数
s.db.Model(&User{}).Where("status = ?", 1).Count(&stats.ActiveUsers)
// 平均年龄
s.db.Model(&User{}).Select("AVG(age)").Row().Scan(&stats.AverageAge)
// 今日新增
today := time.Now().Format("2006-01-02")
s.db.Model(&User{}).
Where("DATE(created_at) = ?", today).
Count(&stats.NewUsersToday)
return &stats, nil
}