gorm查询详细使用

var users []Student
//查询用户名是枫枫的,存储在users中
DB.Where("name = ?", "枫枫").Find(&users)
fmt.Println(users)
//查询名字不是枫枫的
DB.Where("name <> ?", "枫枫").Find(&users)
fmt.Println(users)
// 查询用户名包含 如燕,李元芳的
DB.Where("name in ?", []string{"如燕", "李元芳"}).Find(&users)
fmt.Println(users)
// 查询姓李的
DB.Where("name like ?", "李%").Find(&users)
fmt.Println(users)
// 查询年龄大于23,是qq邮箱的
DB.Where("age > ? and email like ?", "23", "%@qq.com").Find(&users)
fmt.Println(users)
// 查询是qq邮箱的,或者是女的
DB.Where("gender = ? or email like ?", false, "%@qq.com").Find(&users)
fmt.Println(users)

使用结构体查询

使用结构体会过滤零值,如果是查询条件是零值的话,会不考虑这个条件

并且结构体中的条件都是and关系

//结构体查询会过滤零值
	DB.Where(&Student{Name: "元芳", Age: 12}).Find(&users)
	fmt.Println(users)

使用map查询

不会过滤零值

//map不会过滤零值
DB.Where(map[string]any{"name": "元芳", "age": 0}).Find(&users)
fmt.Println(users)

Not

// 排除年龄大于23的
DB.Not("age > 23").Find(&users)
fmt.Println(users)

Or

DB.Or("gender = ?", false).Or(" email like ?", "%@qq.com").Find(&users)
fmt.Println(users)

Select

没有被选中,会被赋零值

DB.Select("name", "age").Find(&users)
fmt.Println(users)
//也可以存入另一个结构体中
type User struct {
  Name string
  Age  int
}
var students []Student
var users []User
DB.Select("name", "age").Find(&students).Scan(&users)
fmt.Println(users)
//这样会查询两次

查询一次的话有两种方法

var users []User
DB.Model(&Student{}).Select("name", "age").Scan(&users)
fmt.Println(users)
var users []User
DB.Table("student").Select("name", "age").Scan(&users)
fmt.Println(users)

排序

var users []Student
DB.Order("age desc").Find(&users)
fmt.Println(users)
// desc    降序
// asc     升序

分页查询

var users []Student
// 一页两条,第1页
DB.Limit(2).Offset(0).Find(&users)
fmt.Println(users)
// 第2页
DB.Limit(2).Offset(2).Find(&users)
fmt.Println(users)
// 第3页
DB.Limit(2).Offset(4).Find(&users)
fmt.Println(users)

更通用的方法

var users []Student
//一页多少条
limit := 2
//第几页
page := 1
offset := (page - 1) * limit
DB.Limit(limit).Offset(offset).Find(&users)
fmt.Println(users)

加个for循环打印出所有的

var users []Student
	limit := 2  // 每页多少条
	page := 1   // 从第一页开始
	offset := 0 // 偏移量
for {
	// 计算偏移量
	offset = (page - 1) * limit

	// 查询当前页的数据
	DB.Limit(limit).Offset(offset).Find(&users)

	// 如果当前页没有数据了,说明已经查询完所有数据
	if len(users) == 0 {
		break
	}

	// 打印当前页的数据
	fmt.Println(users)
    
	// 清空切片,准备下一次查询
	users = []Student{}

	// 增加页码
	page++
}

去重

//去重
var ageList []int
DB.Table("students").Select("age").Distinct("age").Scan(&ageList)
//或者
//DB.Table("students").Select("distinct age").Scan(&ageList)
fmt.Println(ageList)

分组查询

//查询男生的人数和女生的个数
var ageList []int
DB.Table("students").Select("count(id)").Group("gender").Scan(&ageList)
fmt.Println(ageList)

//精确一点
type AggeGroup struct {
  Gender int
  Count  int `gorm:"column:count(id)"`
}
var agge []AggeGroup
//查询男生的个数和女生的个数
DB.Table("students").Select("count(id)", "gender").Group("gender").Scan(&agge)
fmt.Println(agge)

//更精确一点
type AggeGroup struct {
    Gender int
    Count  int    `gorm:"column:count(id)"`
    Name   string `gorm:"column:group_concat(name)"`
}
//GROUP_CONCAT是 MySQL 中的一个聚合函数,用于将分组内的某个字段值连接成一个字符串
var agge []AggeGroup
//查询男生的个数和女生的个数
DB.Table("students").Select("count(id)", "gender", "group_concat(name)").Group("gender").Scan(&agge)
fmt.Println(agge)

执行原生sql

type AggeGroup struct {
  Gender int
  Count  int    `gorm:"column:count(id)"`
  Name   string `gorm:"column:group_concat(name)"`
}

var agge []AggeGroup
DB.Raw(`SELECT count(id), gender, group_concat(name) FROM students GROUP BY gender`).Scan(&agge)

fmt.Println(agge)

子查询

# 原生sql
select * from students where age > (select avg(age) from students);

//相当于
var users []Student
DB.Model(Student{}).Where("age > (?)", DB.Model(Student{}).Select("avg(age)")).Find(&users)
fmt.Println(users)

命名参数

var users []Student
DB.Where("name = @name and age = @age", sql.Named("name", "枫枫"), sql.Named("age", 23)).Find(&users)
DB.Where("name = @name and age = @age", map[string]any{"name": "枫枫", "age": 23}).Find(&users)
fmt.Println(users)

Find到map

var res []map[string]any
DB.Table("students").Find(&res)
fmt.Println(res)

查询引用scope

可以再model层写一些通用的查询方式,这样外界就可以直接调用方法即可

func Age23(db *gorm.DB) *gorm.DB {
  return db.Where("age > ?", 23)
}

func main(){
  var users []Student
  DB.Scopes(Age23).Find(&users)
  fmt.Println(users)
}

<think>好的,用户现在问的是GORM中LIKE的使用方法。我需要先回顾一下之前和用户的对话历史。之前用户询问过如何输出GORM生成的SQL,现在转向查询条件中的LIKE操作,可能是想实现模糊搜索。 首先,用户可能正在开发一个需要搜索功能的项目,比如用户管理,需要根据姓名、邮箱等字段进行模糊查询。他们可能已经掌握了基本的CRUD操作,现在想了解如何在GORM中正确使用LIKE语句。 接下来,我需要考虑GORM中实现LIKE的不同方法。常见的包括使用字符串拼接%、使用`gorm.Expr`,以及处理特殊字符的情况。此外,用户可能对SQL注入有顾虑,所以需要强调参数化查询的重要性,避免直接拼接用户输入。 另外,用户可能想知道不同数据库的适配问题,比如PostgreSQL的ILIKE,或者如何处理大小写敏感的问题。可能需要提到使用`Collate`方法或者自定义排序规则。 还需要考虑示例的清晰度,提供多种场景的代码片段,比如前后模糊匹配、多个条件的组合使用,以及使用结构体或map来构建查询条件。同时,要提醒用户注意通配符的位置对查询性能的影响,比如前导通配符可能导致索引失效。 可能用户在实际使用中遇到特殊字符如%或_时需要转义,这部分需要详细说明,避免查询出错。另外,复合查询中的LIKE使用,比如结合AND和OR,也是常见的应用场景,需要给出示例。 总结一下,回答需要结构清晰,分点列出不同的使用方式,每个部分给出代码示例和说明,强调安全性和性能注意事项,最后总结最佳实践,帮助用户全面理解并正确应用LIKE操作。</think>在 GORM使用 `LIKE` 进行模糊查询主要有以下 6 种典型用法,包含特殊场景处理和性能优化建议: --- ### 一、基础用法(占位符方式) ```go // 前后模糊匹配(推荐安全写法) db.Where("name LIKE ?", "%张%").Find(&users) // 生成 SQL: SELECT * FROM `users` WHERE name LIKE '%张%' // 前缀匹配 db.Where("email LIKE ?", "user%@example.com").Find(&users) // 生成 SQL: SELECT * FROM `users` WHERE email LIKE 'user%@example.com' // 后缀匹配 db.Where("phone LIKE ?", "%8888").Find(&users) ``` --- ### 二、表达式方式(支持复杂条件) ```go // 使用 gorm.Expr 构建表达式 db.Where(gorm.Expr("address LIKE ?", "%北京%")).Find(&users) // 组合多个条件 db.Where( gorm.Expr("(name LIKE ? OR email LIKE ?)", "%john%", "%@gmail.com"), ).Find(&users) ``` --- ### 三、链式调用(结合其他条件) ```go q := db.Model(&User{}). Select("id", "name"). Where("age > ?", 18). Where("name LIKE ?", "李%"). Order("created_at DESC") // 生成 SQL: // SELECT `id`,`name` FROM `users` // WHERE age > 18 AND name LIKE '李%' // ORDER BY created_at DESC ``` --- ### 四、结构体条件(自动忽略零值) ```go type SearchParams struct { Name string Email string `gorm:"column:email_address"` } params := SearchParams{ Name: "%admin%", Email: "%@company.com" } db.Where(params).Find(&users) // 生成 SQL:SELECT * FROM `users` // WHERE `name` LIKE '%admin%' // AND `email_address` LIKE '%@company.com' ``` --- ### 五、Map 条件(灵活字段组合) ```go conditions := map[string]interface{}{ "name LIKE": "%测试%", "status": 1, } db.Where(conditions).Find(&users) // 生成 SQL:SELECT * FROM `users` // WHERE name LIKE '%测试%' AND status = 1 ``` --- ### 六、高级场景处理 #### 1. 大小写不敏感查询(PostgreSQL) ```go db.Where("name ILIKE ?", "%john%").Find(&users) ``` #### 2. 转义特殊字符 ```go // 搜索包含 % 本身的内容 db.Where("comment LIKE ?", "%\\%%").Find(&comments) // 使用双反斜杠转义 // 生成 SQL:SELECT * FROM `comments` WHERE comment LIKE '%\%%' ``` #### 3. 全文索引优化 ```go // 使用 MATCH AGAINST(需要 MySQL 5.6+) db.Where("MATCH(content) AGAINST(? IN BOOLEAN MODE)", "+gorm +like").Find(&articles) ``` --- ### 性能优化建议 1. **索引策略**: - 避免前导通配符 `%xxx`,优先使用 `xxx%` - 对长文本字段考虑前缀索引 ```sql CREATE INDEX idx_name_prefix ON users(name(10)) ``` 2. **参数绑定**: ```go // 错误示范(SQL 注入风险) db.Where(fmt.Sprintf("name LIKE '%%%s%%'", input)) // 正确做法(参数化查询) db.Where("name LIKE ?", "%"+input+"%") ``` 3. **查询缓存**: ```go stmt := db.Where("name LIKE ?", "%张%").Statement stmt.Cache(time.Hour, "user_search_cache") ``` --- ### 最佳实践总结 1. **安全第一**:始终使用参数化查询防止 SQL 注入 2. **模式选择**: - `xxx%`:适合前缀匹配(可用索引) - `%xxx`:适合后缀匹配(需配合倒排索引) - `%xxx%`:全模糊匹配(谨慎使用) 3. **特殊字符处理**:对用户输入进行转义 4. **性能监控**:对频繁使用的 LIKE 查询进行 EXPLAIN 分析 --- 当需要处理更复杂的搜索场景时,建议结合 Elasticsearch 或数据库内置的全文检索功能(如 PostgreSQL 的 tsvector)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值