企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
> gorm查询数据本质上就是提供一组函数,帮我们快速拼接sql语句,尽量减少编写sql语句的工作量 [TOC] ## 测试表 ~~~ CREATE TABLE `food` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '商品id', `title` varchar(100) NOT NULL COMMENT '商品名', `price` float DEFAULT '0' COMMENT '商品价格', `stock` int(11) DEFAULT '0' COMMENT '商品库存', `type` int(11) DEFAULT '0' COMMENT '商品类型', `create_time` datetime NOT NULL COMMENT '商品创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ~~~ ## 模型定义 ~~~ //商品 type Food struct { Id int Title string Price float32 Stock int Type int //mysql datetime, date类型字段,可以和golang time.Time类型绑定, 详细说明请参考:gorm连接数据库章节。 CreateTime time.Time } //为Food绑定表名 func (v Food) TableName() string { return "food" } ~~~ ## 使用gorm链式操作函数查询数据 ### query **Take** > 查询一条记录 ~~~ food := Food{} //等价于:SELECT * FROM `foods` LIMIT 1 db.Take(&food) ~~~ **Find** > 查询多条记录,Find函数返回的是一个数组 ~~~ var foods []Food //等价于:SELECT * FROM `foods` db.Find(&foods) ~~~ **Pluck** > 查询一列值 ~~~ //商品标题数组 var titles []string //返回所有商品标题 //等价于:SELECT title FROM `foods` //Pluck提取了title字段,保存到titles变量 //这里Model函数是为了绑定一个模型实例,可以从里面提取表名。 db.Model(Food{}).Pluck("title", &titles) ~~~ **查询错误处理** > 通过db.Error属性判断查询结果是否出错, Error属性不等于nil表示有错误发生 ~~~ if err := db.Take(&food).Error; err != nil { fmt.Println("查询失败", err) } ~~~ > 查询不到数据, gorm也会当成错误处理 ~~~ err := db.Take(&food).Error if gorm.IsRecordNotFoundError(err) { fmt.Println("查询不到数据") } else if err != nil { //如果err不等于record not found错误,又不等于nil,那说明sql执行失败了。 fmt.Println("查询失败", err) } ~~~ > 或者 ~~~ if db.Take(&food).RecordNotFound() { fmt.Println("查询不到数据") } ~~~ ### where > 语法:`db.Where(query interface{}, args ...interface{})` ~~~ 例子1: //等价于: SELECT * FROM `foods` WHERE (id = '10') LIMIT 1 //这里问号(?), 在执行的时候会被10替代 db.Where("id = ?", 10).Take(&food) //例子2: //等价于: SELECT * FROM `foods` WHERE (id in ('1','2','5','6')) LIMIT 1 //args参数传递的是数组 db.Where("id in (?)", []int{1,2,5,6}).Take(&food) //例子3: //等价于: SELECT * FROM `foods` WHERE (create_time >= '2018-11-06 00:00:00' and create_time <= '2018-11-06 23:59:59') //这里使用了两个问号(?)占位符,后面传递了两个参数替换两个问号。 db.Where("create_time >= ? and create_time <= ?", "2018-11-06 00:00:00", "2018-11-06 23:59:59").Find(&foods) //例子4: //等价于: SELECT * FROM `foods` WHERE (title like '%可乐%') db.Where("title like ?", "%可乐%").Find(&foods) ~~~ ### select > 设置select子句, 指定返回的字段 ~~~ //例子1: //等价于: SELECT id,title FROM `foods` WHERE `foods`.`id` = '1' AND ((id = '1')) LIMIT 1 db.Select("id,title").Where("id = ?", 1).Take(&food) //这种写法是直接往Select函数传递数组,数组元素代表需要选择的字段名 db.Select([]string{"id", "title"}).Where("id = ?", 1).Take(&food) //例子2: //可以直接书写聚合语句 //等价于: SELECT count(*) as total FROM `foods` total := []int{} //Model函数,用于指定绑定的模型,这里生成了一个Food{}变量。目的是从模型变量里面提取表名,Pluck函数我们没有直接传递绑定表名的结构体变量,gorm库不知道表名是什么,所以这里需要指定表名 //Pluck函数,主要用于查询一列值 db.Model(Food{}).Select("count(*) as total").Pluck("total", &total) fmt.Println(total[0]) ~~~ ### order > 设置排序语句,order by子句 ~~~ //例子: //等价于: SELECT * FROM `foods` WHERE (create_time >= '2018-11-06 00:00:00') ORDER BY create_time desc db.Where("create_time >= ?", "2018-11-06 00:00:00").Order("create_time desc").Find(&foods) ~~~ ### limit & Offset > 设置limit和Offset子句,分页的时候常用语句 ~~~ //等价于: SELECT * FROM `foods` ORDER BY create_time desc LIMIT 10 OFFSET 0 db.Order("create_time desc").Limit(10).Offset(0).Find(&foods) ~~~ ### count > Count函数,直接返回查询匹配的行数 ~~~ //例子: total := 0 //等价于: SELECT count(*) FROM `foods` //这里也需要通过model设置模型,让gorm可以提取模型对应的表名 db.Model(Food{}).Count(&total) fmt.Println(total) ~~~ ### 分组 ~~~ //例子: //统计每个商品分类下面有多少个商品 //定一个Result结构体类型,用来保存查询结果 type Result struct { Type int Total int } var results []Result //等价于: SELECT type, count(*) as total FROM `foods` GROUP BY type HAVING (total > 0) db.Model(Food{}).Select("type, count(*) as total").Group("type").Having("total > 0").Scan(&results) //scan类似Find都是用于执行查询语句,然后把查询结果赋值给结构体变量,区别在于scan不会从传递进来的结构体变量提取表名. //这里因为我们重新定义了一个结构体用于保存结果,但是这个结构体并没有绑定foods表,所以这里只能使用scan查询函数。 ~~~ > 提示:Group函数必须搭配Select函数一起使用 ### 直接执行sql语句 > 对于复杂的查询,例如多表连接查询,我们可以直接编写sql语句 ~~~ sql := "SELECT type, count(*) as total FROM `foods` where create_time > ? GROUP BY type HAVING (total > 0)" //因为sql语句使用了一个问号(?)作为绑定参数, 所以需要传递一个绑定参数(Raw第二个参数). //Raw函数支持绑定多个参数 db.Raw(sql, "2018-11-06 00:00:00").Scan(&results) fmt.Println(results) ~~~