04
条件查询
上一小节介绍的查询方式,都没有使用查询条件,本小节内容介绍条件查询,在介绍条件查询之前,先来介绍一下 expr,expr 是 QuerySeter 用于描述字段和描述sql 操作符的一种表达方式。
字段组合的前后顺序依照表的关系,比如 User 表拥有 Profile 的外键,那么对 User 表查询对应的 Profile.Age 为条件,则使用 Profile__Age。
注意,字段的分隔符号使用双下划线 __,除了描述字段, expr 的尾部可以增加操作符以执行对应的 sql 操作。比如 Profile__Age__gt 代表 Profile.Age > 18 的条件查询。
expr 示例代码:
qs.Filter("id", 1) // WHERE id = 1 qs.Filter("profile__age", 18) // WHERE profile.age = 18 qs.Filter("Profile__Age", 18) // 使用字段名和 Field 名都是允许的 qs.Filter("profile__age__gt", 18) // WHERE profile.age > 18 qs.Filter("profile__age__gte", 18) // WHERE profile.age >= 18 qs.Filter("profile__age__in", 18, 20) // WHERE profile.age IN (18, 20) qs.Filter("profile__age__in", 18, 20).Exclude("profile__lt", 1000) // WHERE profile.age IN (18, 20) AND NOT profile_id < 1000
注释后面将描述对应的 sql 语句,仅仅是描述 expr 的类似结果,并不代表实际生成的语句。
表达式和操作符
在介绍 QuerySeter 的方法之前,先介绍表达式和操作符,表达式和操作符适用于 QuerySeter 的所有方法。
表达式
- 等于
- 大于 gt
- 大于等于 gte
- 小于 lt
- 小于等于 lte
- IN
- isnull (true:isnull / false:is not null)
操作符
- exact 等于(区分字母大小写)
iexact 等于(不区分大小写)
contains Like(区分大小写)
icontains Like( 不区分大小写)
startswith (前置模糊查询,区分大小写)
istartswith(前置模糊查询,不区分大小写)
endswith(后置模糊查询,区分大小写)
iendswith(后置模糊查询,不区分大小写)
QuerySeter 的方法
Filter 包含
Filter 方法用来过滤查询结果,起到「包含条件」的作用。
Exclude 排除
Exclude 方法用来过滤查询结果,起到「排除条件」的作用。
Limit 限制条数
Limit 方法限制最大返回的记录数,默认值为 1000。第二个参数可以设置 offset,需要特别注意的是,这里的 limit / offset 和原生 sql 中的 limit / offset 是反过来的。
Offset 偏移
Offset 方法用来设置偏移量。
OrderBy 排序 "column" means ASC, "-column" means DESC.
OrderBy 方法用于排序,参数使用 expr 表达方式,默认是 ASC 排序规则,在 expr 前面用减号「-」表示 DESC 排序规则。
Distinct 方法
Distinct 方法返回指定字段不重复的查询结果。
Exist 是否存在
Exist 方法用于判断符合查询条件的结果是否存在。
示例代码:
func (u *UserController) Read() { o := orm.NewOrm() // 条件查询 var users []models.User // Filter 包含 // 表达式和操作符 // 等于 err := o.QueryTable(new(models.User)).Filter("id", 2).One(&users) // 大于 // num, err := o.QueryTable(new(models.User)).Filter("id__gt", 9).All(&users) // 大于等于 // num, err := o.QueryTable(new(models.User)).Filter("id__gte", 9).All(&users) // 小于 // num, err := o.QueryTable(new(models.User)).Filter("id__lt", 5).All(&users) // 小于等于 // num, err := o.QueryTable(new(models.User)).Filter("id__lte", 5).All(&users) // IN // num, err := o.QueryTable(new(models.User)).Filter("id__in", 2, 4).All(&users) // isnull (true:isnull / false: is not null) // num, err := o.QueryTable(new(models.User)).Filter("id__isnull", false).All(&users) // num, err := o.QueryTable(new(models.User)).Filter("id__isnull", true).All(&users) // exact 等于(区分字母大小写) // num, err := o.QueryTable(new(models.User)).Filter("name__exact", "frank").All(&users) // iexact 等于(不区分大小写) // num, err := o.QueryTable(new(models.User)).Filter("name__iexact", "frank").All(&users) // contains Like(区分大小写) // num, err := o.QueryTable(new(models.User)).Filter("name__contains", "frank").All(&users) // icontains Like( 不区分大小写) // num, err := o.QueryTable(new(models.User)).Filter("name__icontains", "frank").All(&users) // startswith (前置模糊查询,区分大小写) // num, err := o.QueryTable(new(models.User)).Filter("name__startswith", "fran").All(&users) // istartswith(前置模糊查询,不区分大小写) // num, err := o.QueryTable(new(models.User)).Filter("name__istartswith", "fran").All(&users) // endswith(后置模糊查询,区分大小写) // num, err := o.QueryTable(new(models.User)).Filter("name__endswith", "er").All(&users) // iendswith(后置模糊查询,不区分大小写) // num, err := o.QueryTable(new(models.User)).Filter("name__iendswith", "er").All(&users) // Exclude 排除 // num, err := o.QueryTable(new(models.User)).Exclude("name__exact", "frank").All(&users) // Limit 限制条数 // num, err := o.QueryTable(new(models.User)).Limit(4).All(&users) // Offset 偏移 // num, err := o.QueryTable(new(models.User)).Offset(4).All(&users) // OrderBy 排序 "column" means ASC, "-column" means DESC. // num, err := o.QueryTable(new(models.User)).OrderBy("id").All(&users) // num, err := o.QueryTable(new(models.User)).OrderBy("-id").All(&users) // Distinct 去重 // num, err := o.QueryTable(new(models.User)).Filter("id__gt", 9).Distinct().All(&users, "Age") // Exist 是否存在 // isExisted := o.QueryTable(new(models.User)).Filter("name__exact", "frank1").Exist() // fmt.Println("isExisted:", isExisted) if err != nil { log.Fatalln(err.Error()) return } fmt.Printf("user:%+v\n", users) }
05
原生 SQL 查询
beego ORM 原生 SQL 查询,通过获取一个 RawSeter 对象,使用 RawSeter 对象的 Raw 方法,实现原生 SQL 查询。
Raw 方法,参数 1 是原生 sql 语句的字符串,参数 2 是原生 sql 语句的参数,该参数支持模型结构体,切片和数组。
RawSeter 接口的方法:
type RawSeter interface { Exec() (sql.Result, error) QueryRow(containers ...interface{}) error QueryRows(containers ...interface{}) (int64, error) SetArgs(...interface{}) RawSeter Values(container *[]Params, cols ...string) (int64, error) ValuesList(container *[]ParamsList, cols ...string) (int64, error) ValuesFlat(container *ParamsList, cols ...string) (int64, error) RowsToMap(result *Params, keyCol string, valueCol string) (int64, error) RowsToStruct(ptrStruct interface{}, keyCol string, valueCol string) (int64, error) Prepare() (RawPreparer, error) }
接下来,我们来介绍一下 QueryRow 方法和 QueryRows 方法。
QueryRow 方法
QueryRow 方法返回单条查询数据,不定长参数接收指针类型。
示例代码:
func (u *UserController) Read() { o := orm.NewOrm() var user models.User err := o.Raw("SELECT id,name,age FROM beego_user WHERE id = ?", 2).QueryRow(&user) if err != nil { log.Fatalln(err.Error()) return } fmt.Printf("user:%+v\n", user) }
QueryRows 方法
QueryRows 方法返回多条查询数据,不定长参数接收指针类型。返回结果是查询结果集的数量和错误。
示例代码:
func (u *UserController) Read() { o := orm.NewOrm() var users []models.User ids := []int{1,3,5} num, err := o.Raw("SELECT id,name,age FROM beego_user WHERE id IN (?,?,?)", ids).QueryRows(&users) if err != nil { log.Fatalln(err.Error()) return } fmt.Printf("nums:%d user:%+v\n", num, users) }
06
总结
本文主要介绍 beego ORM 的读操作,包含普通查询、高级查询和原生 SQL 查询,先是介绍了普通查询,然后是介绍高级查询,包含 expr 表达式,QuerySeter 接口和其部分方法的使用,最后介绍了 RawSeter 接口和其部分方法的使用。限于篇幅,没有介绍关联查询和构造查询,关于未提及的内容,读者朋友可以参考官方手册。