GORM高级查询
GORM高级查询
准备数据
type Student struct {
ID uint `gorm:"size:3"`
Name string `gorm:"size:8"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func (stu Student) TableName() string {
return "student"
}
func main(){
var studentList []Student
DB.Find(&studentList).Delete(&studentList)
studentList = []Student{
{ID: 1, Name: "李元芳", Age: 32, Email: PtrString("lyf@yf.com"), Gender: true},
{ID: 2, Name: "张武", Age: 18, Email: PtrString("zhangwu@lly.cn"), Gender: true},
{ID: 3, Name: "枫枫", Age: 23, Email: PtrString("ff@yahoo.com"), Gender: true},
{ID: 4, Name: "刘大", Age: 54, Email: PtrString("liuda@qq.com"), Gender: true},
{ID: 5, Name: "李武", Age: 23, Email: PtrString("liwu@lly.cn"), Gender: true},
{ID: 6, Name: "李琦", Age: 14, Email: PtrString("liqi@lly.cn"), Gender: false},
{ID: 7, Name: "晓梅", Age: 25, Email: PtrString("xiaomeo@sl.com"), Gender: false},
{ID: 8, Name: "如燕", Age: 26, Email: PtrString("ruyan@yf.com"), Gender: false},
{ID: 9, Name: "魔灵", Age: 21, Email: PtrString("moling@sl.com"), Gender: true},
}
DB.Create(&studentList)
}
func PtrString(email string) *string {
return &email
}
Where
stud := []Student{}
// 查询用户名是枫枫的
DB.Where("name = ?", "枫枫").Find(&stud)
fmt.Printf("%v\n", stud)
//fmt.Printf("%v\n", *stud[0].Email)
// 查询用户名不是枫枫的
DB.Where("not name = ?", "枫枫").Find(&stud)
fmt.Printf("%v\n", stud)
//for _, v := range stud {
// fmt.Println(*v.Email)
//}
// 查询用户名包含 如燕,李元芳的
DB.Where("name in ?", []string{"如燕", "李元芳"}).Find(&stud)
fmt.Printf("%v\n", stud)
// 查询姓李的
DB.Where("name like ?", "李%").Find(&stud)
fmt.Printf("%v\n", stud)
// 查询年龄大于23,是qq邮箱的
DB.Where("age > ? and email like ?", 23, "%@qq.com").Find(&stud)
fmt.Printf("%v\n", stud)
// 查询是qq邮箱的,或者是女的
DB.Where("email like ? or gender = ?", "@qq.com", false).Find(&stud)
fmt.Printf("%v\n", stud)
使用结构体查询
使用结构体查询,会过滤零值
并且结构体中的条件都是and关系
// 会过滤零值
DB.Where(&Student{Name: "李元芳", Age: 0}).Find(&users)
fmt.Println(users)
/*
SELECT * FROM `student` WHERE `student`.`name` = '李元芳'
age=0的条件不生效
*/
使用map查询
不会过滤零值
DB.Where(map[string]any{"name": "李元芳", "age": 0}).Find(&users)
// SELECT * FROM `student` WHERE `age` = 0 AND `name` = '李元芳
fmt.Println(users)CopyErrorOK!
Not条件
和where中的not等价
// 排除年龄大于23的
DB.Not("age > 23").Find(&users)
fmt.Println(users)CopyErrorOK!
Or条件
和where中的or等价
stud := []Student{}
DB.Or("gender = ?", false).Or(" email like ?", "%@qq.com").Find(&users)
fmt.Println(users)
Select选择字段
stud := []Student{}
DB.Select("name", "age").Find(&users)
fmt.Println(users)
// 没有被选中,会被赋零值
/*
SELECT `name` FROM `student`
[{0 李元芳 0 false <nil>} {0 张武 0 false <nil>} {0 枫枫 0 false <nil>} {0 刘大 0 false <nil>} {0 李武 0 false <nil>} {0 李琦 0 false <nil>} {0 晓梅 0 如燕 0 false <nil>} {0 魔灵 0 false <nil>}]
只有name字段有值,其余字段都是对应数据类型的默认值
*/
可以使用扫描Scan,将选择的字段存入另一个结构体中
type User struct {
Name string
Age int
}
stud := []Student{}
userList := []User{}
DB.Select([]string{"name", "age"}).Find(&stud).Scan(&userList)
// 指定表名
DB.Table("student").Select([]string{"name", "age"}).Scan(&userList)
// Model传入表的对象
DB.Model(Student{}).Select([]string{"name", "age"}).Scan(&userList)
fmt.Println(userList)
Scan是根据column列名进行扫描的
type User struct {
Name123 string `gorm:"column:name"`
Age int
}
stud := []Student{}
DB.Table("students").Select("name", "age").Scan(&stud)
fmt.Println(stud)
排序
根据年龄倒序
stud := []Student{}
DB.Order("age desc").Find(&stud)
fmt.Println(stud)
// desc 降序
// asc 升序
注意order的顺序
分页查询
stud := []Student{}
// 一页两条,第1页
DB.Limit(2).Offset(0).Find(&stud)
fmt.Println(stud)
// 第2页
DB.Limit(2).Offset(2).Find(&stud)
fmt.Println(stud)
// 第3页
DB.Limit(2).Offset(4).Find(&stud)
fmt.Println(stud)
通用写法
stud := []Student{}
// 一页多少条
limit := 2
// 第几页
page := 1
offset := (page - 1) * limit
DB.Limit(limit).Offset(offset).Find(&stud)
fmt.Println(stud)
去重
stud := []Student{}
DB.Table("student").Select("age").Distinct("age").Scan(&stud)
fmt.Println(stud)
或者
DB.Table("student").Select("distinct age").Scan(&stud)
分组查询
var ageList []int
// 查询男生的个数和女生的个数
DB.Table("students").Select("count(id)").Group("gender").Scan(&ageList)
fmt.Println(ageList)
/*
结果:[6 3]
*/
有个问题,哪一个是男生个数,那个是女生个数
所以我们应该精确一点
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)"`
}
var agge []AggeGroup
// 查询男生的个数和女生的个数
DB.Table("students").Select("count(id)", "gender", "group_concat(name)").Group("gender").Scan(&agge)
fmt.Println(agge)
也可以写成
type AggeGroup struct {
Gender int
Count int
Name string
}
var agge []AggeGroup
// 查询男生的个数和女生的个数
DB.Table("student").Select("count(id) as count", "gender", "group_concat(name) as 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);
使用gorm编写
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)
}