title: Beego脱坑(十四)ORM高级查询
tags: go,beego,orm
author : Clown95
本文将讲述beego ORM的一些高级查询,这也是ORM最核心的部分,本文所有的操作都基于下面的student
表
Operators
在beego ORM中也有类似于SQL语句中的操作符,欲善其事,必利其器,我们先来了解他们,beego ORM目前支持的操作符为:
操作符 | 说明 | 等同Sql操作符 |
---|---|---|
gt | greater的缩写,表示大于的意思 | > |
gte | greater than or equal的缩写,即大于等于 | >= |
lt | less than的缩写,表示小于 | < |
lte | less thanor equal的缩写,小于等于 | <= |
in | 等同与sql语言中的in | in |
exact | 等于 | = |
contains | 包含,一般用于字符类型,如包含某某字符 | like '%查询内容%' |
startswith | 以…起始,一般用于字符类型,如从什么字符开始 | like '开始字符%' |
endswith | 以…结束 ,一般用于字符类型,如以什么字符结束 | like '%结束字符' |
isnull | 表示改字段不能为空 |
在beego中 操作符前面添加 字母 i
表示忽略大小写,如 iexact、icontains 、istartswith 和iendswith
exact
我们最先演示下exact 它相当于 = ,现在我们需要通过它查询出 stu_id =3 的一条数据。
func (this *OperatorsController) GetExact() {
orm := orm.NewOrm()
// 获取表句柄
stu := Student{}
qs := orm.QueryTable("student")
// select * from student where id =3;
err := qs.Filter("stu_id__exact", 3).One(&stu) // 过滤器
if err != nil {
this.Ctx.WriteString(strconv.Itoa(stu.StuId) + " " + stu.Name + " " + stu.Age + " " + stu.Hobby)
}else{
this.Ctx.WriteString("查询失败")
}
}
上面的代码相当于sql语句 :
select * from student where id =3;
QueryTable("student")
: 返回student
表的QuerySeter 对象。ORM 以 QuerySeter 来组织查询,每个返回 QuerySeter 的方法都会获得一个新的 QuerySeter 对象;Filter("stu_id__exact" ,3)
: 用来过滤查询结果,起到包含条件
的作用,第一个参数是我匹配规则,第二个参数是我们匹配的值 ; 使用如果使用操作符,字段和操作符直接使用两个"_"连接,具体格式为:字段__操作符
;One(&stu)
: 返回单条记录 ,参数一般是结构体对象。
gte
现在我们来使用 gte
获取 age>=25岁的所有数据, 下面我们看代码。
func (this *OperatorsController) GetAllGte() {
orm := orm.NewOrm()
var stus = []*Student{}
// 获取表句柄
qs := orm.QueryTable("student")
// select * from student where age>=25;
n, err := qs.Filter("age__gte", 20).All(&stus) // 过滤器
if err == nil && n > 0 {
for i := 0; i < len(stus); i++ {
this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
}
} else {
this.Ctx.WriteString("查询失败")
}
}
上面的代码相当于sql语句:
select * from student where age>=25;
All(&stus)
: 返回对应的结果集对象。 和One不一样的是,All返回所有符合条件的数据,参数是指针切片( []Type 或者[]*Type ),返回数据cols和error
in
现在我们通过 in 查询 stu_id 为 1、4、5、10的数据集。
func (this *OperatorsController) GetIn() {
orm := orm.NewOrm()
var stus = []*Student{}
// 获取表句柄
qs := orm.QueryTable("student")
// select * from student where stu_id in(1,4,5,10);
n, err := qs.Filter("stu_id__in",1,4,5,10 ).All(&stus) // 过滤器
if err == nil && n > 0 {
for i := 0; i < len(stus); i++ {
this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
}
} else {
this.Ctx.WriteString("查询失败")
}
}
上面的代码相当于sql语句:
select * from student where stu_id in(1,4,5,10);
contains
接着我们使用 contains 来查询 name中包含 "小" 字的数据集。
func (this *OperatorsController) GetContains() {
orm := orm.NewOrm()
var stus = []*Student{}
// 获取表句柄
qs := orm.QueryTable("student")
// select * from student where name like '小%';
n, err := qs.Filter("name__contains", "小").All(&stus) // 过滤器
if err == nil && n > 0 {
for i := 0; i < len(stus); i++ {
this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
}
} else {
this.Ctx.WriteString("查询失败")
}
}
上面的代码相当于sql语句:
select * from student where name like '小%';
操作符我们就演示到这里,其他的几个用法都大同小异,大家可以自己拓展。
高级查询接口
高级查询接口我们在 Operators 部分里面,使用过 Filter、One、All
这三个了。我们就不在重复介绍了,我们主要来了解下其他的接口函数。
方法 | 说明 |
---|---|
Exclude | 用来过滤查询结果,起到 排除条件的作用,相当于!Filter |
Limit | 限制最大返回数据行数 |
Offset | 设置偏移行数 |
GroupBy | 数据分组 |
OrderBy | 数据排序 |
Distinct | 获取不重复的数据 |
Count | 依据当前的查询条件,返回结果行数 |
Exist | 判断查询的数据是否存在 |
Values | 返回结果集数据,存储到map中 |
ValuesList | 顾名思义,返回的结果集以slice存储 |
PrepareInsert | 用于批量插入数据 |
Delete | 依据当前查询条件,进行批量删除操作 |
Update | 依据当前查询条件,进行批量更新操作 |
Exclude
现在我们来使用Exclude 排除 年龄小于等于25
的数据.
func (this * ADvancedApiController) GetExclude(){
orm := orm.NewOrm()
var stus = []*Student{}
// 获取表句柄
qs := orm.QueryTable("student")
//select * from student where not age <=25 ;
n, err := qs.Exclude("age__lte",25).All(&stus)
if err == nil && n > 0 {
for i := 0; i < len(stus); i++ {
this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
}
} else {
this.Ctx.WriteString("查询失败")
}
}
上面的代码相当于sql语句:
select * from student where not age <=25 ;
Limit
有时候数据过多,我们只想显示部分数据,比如现在我们只需要显示前5个数据
func (this * ADvancedApiController) GetLimit(){
orm := orm.NewOrm()
var stus = []*Student{}
// 获取表句柄
qs := orm.QueryTable("student")
//select * from student limit 5 ;
n, err := qs.Limit(5) .All(&stus)
if err == nil && n > 0 {
for i := 0; i < len(stus); i++ {
this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
}
} else {
this.Ctx.WriteString("查询失败")
}
}
上面的代码相当于sql语句:
select * from student limit 5 ;
当然我们还可以设置偏移量来设置分页 ,我们来修改Limit,显示6-10的数据:
n, err := qs.Limit(5,5) .All(&stus)
GroupBy
通过 age 进行分组
func (this * ADvancedApiController) GetGroupBy(){
orm := orm.NewOrm()
var stus = []*Student{}
qs := orm.QueryTable("student")
n, err := qs.GroupBy("age").All(&stus)
if err == nil && n > 0 {
for i := 0; i < len(stus); i++ {
this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
}
} else {
this.Ctx.WriteString("查询失败")
}
}
OrderBy
通过 age 和 stu_id 进行排序 表达式前面使用 "-" 代表降序排序
func (this * ADvancedApiController) GetOrderBy(){
orm := orm.NewOrm()
var stus = []*Student{}
qs := orm.QueryTable("student")
n, err := qs.OrderBy("-age","stu_id").All(&stus)
if err == nil && n > 0 {
for i := 0; i < len(stus); i++ {
this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
}
} else {
this.Ctx.WriteString("查询失败")
}
}
Count
使用Count 查询有多少行数据
func (this *ADvancedApiController) GetCount() {
orm := orm.NewOrm()
//select count(*) from student;
n, err := orm.QueryTable("student").Count()
if err != nil {
this.Ctx.WriteString("查询出错!\n")
return
}else {
this.Ctx.WriteString("n = " + strconv.Itoa(int(n)))
}
}
上面的代码相当于sql语句:
select count(*) from student;
Exist
我们用 Exist 判断 stu_id =8 和 stu_id =15 的数据是否存在
func (this *ADvancedApiController) GetExist() {
orm := orm.NewOrm()
qs := orm.QueryTable("student")
flag := qs.Filter("stu_id", 8).Exist()
if flag {
this.Ctx.WriteString("stu_id=8 存在\n")
}else {
this.Ctx.WriteString("stu_id=8 不存在\n")
}
flag = qs.Filter("stu_id", 15).Exist()
if flag {
this.Ctx.WriteString("stu_id=15 存在\n")
}else {
this.Ctx.WriteString("stu_id=15 不存在\n")
}
}
Values
我们还可以 使用Values 返回结果集的 key => value 值 ,key 为Model里的Field name, value的值是interface{}类型,如果你要将value赋值给struct中的某字段,需要根据结构体对应字段类型使用断言获取真实值。
func (this *ADvancedApiController) GetValues() {
//将每一条记录的字段作为键,数据作为值存入map中,每个map就是一条记录。
var maps []orm.Params //[map, map, map]
orm := orm.NewOrm()
_, err := orm.QueryTable("student").Values(&maps, )
if err != nil {
this.Ctx.WriteString("查询出错!")
return
}
for _, m := range maps {
this.Ctx.WriteString(m["Name"].(string) + " " + m["Age"].(string) + " " + m["Hobby"].(string) + "\n")
}
}
当然我们还可以直接指定 expr 级联返回需要的数据
func (this *ADvancedApiController) GetValuesField() {
//将每一条记录的字段作为键,数据作为值存入map中,每个map就是一条记录。
var maps []orm.Params //[map, map, map]
orm := orm.NewOrm()
_, err := orm.QueryTable("student").Values(&maps, "Name","Hobby")
if err != nil {
this.Ctx.WriteString("查询出错!")
return
}
for _, m := range maps {
this.Ctx.WriteString(m["Name"].(string) + " " + m["Hobby"].(string) + "\n")
}
}
ValuesList
顾名思义,返回的结果集以slice存储,结果的排列与 Model 中定义的 Field 顺序一致,返回的每个元素值以 string 保存。
func (this *ADvancedApiController) GetValuesList() {
var list []orm.ParamsList
orm := orm.NewOrm()
_, err := orm.QueryTable("student").ValuesList(&list, "Name", "Age", "Hobby")
if err != nil {
this.Ctx.WriteString("查询出错!")
return
}
for _, row := range list {
for _, col := range row {
this.Ctx.WriteString(col.(string) + " ")
}
this.Ctx.WriteString("\n")
}
}
PrepareInsert
我们使用PrepareInsert 在添加点数据,并且我们多提交一次数据,方便演示下面的批量删除
func (this *ADvancedApiController) GetPrepareInsert() {
var stus []*Student
stu1 := Student{Name:"银之介", Age:"60", Hobby:"辣妹"}
stu2 := Student{Name:"正男", Age:"5", Hobby:"小爱"}
stu3 := Student{Name:"阿呆", Age:"6", Hobby:"甩鼻涕"}
stu4 := Student{Name:"园长", Age:"56", Hobby:"园艺"}
stus = append(stus, &stu1, &stu2, &stu3, &stu4)
orm := orm.NewOrm()
// insert into student(name, age.hobby) values("银之介", "60", "辣妹"), (正男", "5", "小爱");
insert, _ := orm.QueryTable("student").PrepareInsert()
for _, stu := range stus {
_, err := insert.Insert(stu)
if err != nil {
fmt.Println("插入错误!\n")
continue
}
}
insert.Close()
this.Ctx.WriteString("插入结束!\n")
}
上面的代码相当于sql语句:
insert into student(name, age.hobby) values("银之介", "60", "辣妹"), ....,(园长", "56", "园艺");
Delete
还记得我们刚刚多提交了一次数据插入吗?我们原来的数据stu_id 最大为11, 所以我们删除 stu_id >11 的数据
func (this *ADvancedApiController) GetDelete() {
orm := orm.NewOrm()
qs:= orm.QueryTable("student")
n,err:=qs.Filter("stu_id__gt",11).Delete()
if err == nil&& n>0 {
this.Ctx.WriteString("删除成功!\n")
} else {
this.Ctx.WriteString("删除失败!\n")
}
}
Update
现在我们来批量更新下数据,下面我们需要把 stu_id=5 的 Hobby 改为 学习。
func (this *ADvancedApiController) GetUpdate() {
orm1 := orm.NewOrm()
qs:= orm1.QueryTable("student")
n,err:=qs.Filter("stu_id",5).Update(orm.Params{
"hobby": "学习",
})
if err == nil&& n>0 {
this.Ctx.WriteString("修改成功!\n")
} else {
this.Ctx.WriteString("修改失败!\n")
}
}
看到这里大家应该基本掌握接口的用法了,还有其他部分没演示的,请自行拓展我实在不想写了。