检索单个对象

GORM 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件

// 获取第一条记录(主键升序)
db.First(&user) // SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1 // 获取第一条记录,没有指定排序字段
db.Take(&user) // SELECT * FROM `users` LIMIT 1 // 获取最后一条记录,主键降序
db.Last(&user) // SELECT * FROM `users` ORDER BY `users`.`id` DESC LIMIT 1
result := db.Last(&user)
fmt.Println(result.RowsAffected) // 返回找到的记录数
fmt.Println(result.Error) // return error or nil
b := errors.Is(result.Error, gorm.ErrRecordNotFound) // 判断错误类型,如果是此错误类型,返回true,否则返回false
fmt.Println(b)
如果你想避免ErrRecordNotFound错误,你可以使用Find,比如db.Limit(1).Find(&user),Find方法可以接受struct和slice的数据。

  

First 和 Last 会根据主键排序,分别查询第一条和最后一条记录。 只有在目标 struct 是指针或者通过 db.Model() 指定 model 时,该方法才有效。 此外,如果相关 model 没有定义主键,那么将按 model 的第一个字段进行排序。

// 有效,因为目标是结构体指针
db.First(&user)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1 // 有效,因为通过db.Model() 指定了model
var result map[string]interface{}
db.Model(new(User)).First(&result)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
// 无效
var result map[string]interface{}
db.Table("users").First(&result)
fmt.Println(result) // 输出:map[]
// 配合Take无效
var result map[string]interface{}
db.Table("users").Take(&result)

// 未指定主键,会根据第一个字段排序(即:`Code`)
type Language struct {
Code string
Name string
}
db.First(&Language{})
// SELECT * FROM `languages` ORDER BY `languages`.`code` LIMIT 1

  

用主键检错

  如果主键是数字类型,您可以使用内联条件来检索对象,传入字符串参数时,需要特别注意 SQL 注入问题

db.First(&user, 2)
// SELECT * FROM `users` WHERE `users`.`id` = 2 ORDER BY `users`.`id` LIMIT 1
db.First(&user, "2")
// SELECT * FROM `users` WHERE `users`.`id` = 2 ORDER BY `users`.`id` LIMIT 1
db.Find(&users, []int{1, 2})
// SELECT * FROM `users` WHERE `users`.`id` IN (1,2)

 如果主键是字符串(例如像 uuid),查询将被写成这样:

db.First(&user, "uuid = ?", "00000000-0000-0000-0000-000000000000")
// SELECT * FROM `users` WHERE uuid = '00000000-0000-0000-0000-000000000000' ORDER BY `users`.`id` LIMIT 1

  

检索全部对象

result := db.Find(&users)
// SELECT * FROM `users`
myPrint(result.RowsAffected)  // 返回的记录行数,相当于 len(users)
myPrint(result.Error) // return error

  

String 条件

// 获取第一条匹配的记录
db.Where("name = ?", "老王").First(&user)
// SELECT * FROM `users` WHERE name = '老王' ORDER BY `users`.`id` LIMIT 1

// 获取全部匹配的记录
db.Where("name = ?", "老王").Find(&users)
// SELECT * FROM `users` WHERE name = '老王'

// IN
db.Debug().Where("age IN (?)", []uint8{10, 55}).Find(&users)
// SELECT * FROM `users` WHERE age IN (10,55)

// LIKE
db.Debug().Where("age LIKE ?", "%0%").Find(&users)
// SELECT * FROM `users` WHERE age LIKE  '%0%'

// AND
db.Debug().Where("age=? AND name=?", 20, "老王").Find(&users)
// SELECT * FROM `users` WHERE age=20 AND name='老王'

// TIME
db.Debug().Where("created_at < ?", time.Now()).Find(&users)
// SELECT * FROM `users` WHERE created_at < '2021-11-17 13:34:51.519'
// BETWEEN
db.Debug().Where("age BETWEEN ? AND ?", 10, 19).Find(&users)
// SELECT * FROM `users` WHERE age BETWEEN 10 AND 19

  

Struct & Map 条件

// struct

var users []User
db.Debug().Where(&User{Name: sql.NullString{"老王", true}, Age: 20}).Find(&users)
// SELECT * FROM `users` WHERE `users`.`name` = '老王' AND `users`.`age` = 20

// map
db.Debug().Where(map[string]interface{}{
"name": sql.NullString{"李四", true}, "age": 10,
}).First(&user)
// SELECT * FROM `users` WHERE `age` = 10 AND `name` = '李四' ORDER BY `users`.`id` LIMIT 1
// 主键切片条件
var users []User
db.Debug().Where([]uint{1, 5}).Find(&users)
// SELECT * FROM `users` WHERE `users`.`id` IN (1,5)

  注意:当使用结构体作为查询条件时,GORM只会查询非零值的字段,这意味着如果您的字段为0、false、""、或其它零值时,该字段不会被用于构建查询条件,例如:

db.Debug().Where(&User{Name: sql.NullString{"老王", true}, Age: 0}).Find(&users)
// SELECT * FROM `users` WHERE `users`.`name` = '老王'

  如果你想包含零值的查询条件,你可以使用map,其会包含所有key-value的查询条件

db.Debug().Where(map[string]interface{}{
"name": sql.NullString{"老王", true}, "age": 0,
}).Find(&users)
// SELECT * FROM `users` WHERE `age` = 0 AND `name` = '老王'

  

指定结构体查询字段

  当使用struct进行查询时,你可以通过想where()传入struct来指定查询条件的字段、值、表名,例如

db.Debug().Where(&User{Name: sql.NullString{"老王", true}}, "name", "Age").Find(&users)
// SELECT * FROM `users` WHERE `users`.`name` = '老王' AND `users`.`age` = 0

db.Debug().Where(&User{Name: sql.NullString{"老王", true}, Age: 20},  "age").Find(&users)
// SELECT * FROM `users` WHERE `users`.`age` = 20

  也就是说where里面放的结构体无论有几个字段程序不管,最终只会按照结构体后面的参数字段进行条件查询

内联条件

  查询条件也可以被内联到First或Find之类的方法中,其用法类似于Where

// 根据主键获取记录,如果是非整型主键
db.Debug().First(&user, "ID = ?", 5)
// SELECT * FROM `users` WHERE ID = 5 ORDER BY `users`.`id` LIMIT 1

// plain sql
db.Debug().Find(&users, "name = ?", "老王")
// SELECT * FROM `users` WHERE name = '老王'
db.Debug().Find(&users, "name <> ? AND age = ?", "老王", 20)
// SELECT * FROM `users` WHERE name <> '老王' AND age = 20

// struct
db.Debug().Find(&users, &User{Name: sql.NullString{"赵六", true}})
// SELECT * FROM `users` WHERE `users`.`name` = '赵六'

// map
db.Debug().Find(&users, map[string]interface{}{
"age": 20,
})
// SELECT * FROM `users` WHERE `age` = 20

  

Not 条件

  构建not条件,用法与Where类型

db.Debug().Not("name <> ?", "赵六").First(&user)
// SELECT * FROM `users` WHERE NOT name <> '赵六' ORDER BY `users`.`id` LIMIT 1

// Not IN
db.Debug().Not("name IN (?)", []string{"老王", "李四"}).First(&user)
// SELECT * FROM `users` WHERE NOT name IN ('老王','李四') ORDER BY `users`.`id` LIMIT 1

// map
db.Debug().Not(map[string]interface{}{
"name": []string{"老王", "李四"},
}).First(&user)
// SELECT * FROM `users` WHERE `name` NOT IN ('老王','李四') ORDER BY `users`.`id` LIMIT 1

// struct
db.Debug().Not(User{Age: uint8(10), Name: sql.NullString{"老王", true}}).Find(&users)
// SELECT * FROM `users` WHERE (`users`.`name` <> '老王' AND `users`.`age` <> 10)

// 不在主键切片中的记录
db.Debug().Not([]uint{1, 2, 3, 5}).Find(&users)
// SELECT * FROM `users` WHERE `users`.`id` NOT IN (1,2,3,5)

  

Or 条件

db.Debug().Where("name = ?", "赵六").Or("age = ?", 10).Find(&users)
// SELECT * FROM `users` WHERE name = '赵六' OR age = 10

// struct
db.Debug().Where("name = ?", "赵六").Or(&User{Age: 55}).Find(&users)
// SELECT * FROM `users` WHERE name = '赵六' OR `users`.`age` = 55

// map
db.Debug().Where("name = ?", "赵六").Or(map[string]interface{}{
"age": 55,
}).Find(&users)
// SELECT * FROM `users` WHERE name = '赵六' OR `age` = 55

  

选择特定字段

  Select 允许您指定从数据库中检索哪些字段, 默认情况下,GORM 会检索所有字段。

db.Debug().Select("name", "age").Find(&users)
// SELECT `name`,`age` FROM `users`

db.Debug().Select([]string{"name", "age"}).Find(&users)
// SELECT `name`,`age` FROM `users`

  

Order

  指定从数据库检索记录时的排序方式

db.Debug().Order("age asc, name desc").Find(&users)
// SELECT * FROM `users` ORDER BY age asc, name desc

// 多个order
db.Debug().Order("age desc").Order("name").Find(&users)
// SELECT * FROM `users` ORDER BY age desc,name

  

Limit & Offset

  limit 指定获取记录的最大数量 Offset 指定在开始返回记录之前要跳过的记录数量

db.Debug().Limit(3).Find(&users)
// SELECT * FROM `users` LIMIT 3

// 通过-1消除limit条件
db.Debug().Limit(1).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM `users` LIMIT 1
// SELECT * FROM `users`

db.Debug().Limit(1).Offset(3).Find(&users)
// SELECT * FROM `users` LIMIT 1 OFFSET 3

// 通过-1消除Offset条件
db.Debug().Offset(3).Offset(-1).Find(&users)
// SELECT * FROM `users`

  注意:Offset要和Limit一起使用,单独使用会报错:Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '3' at line 1

Group By & Having

type Result struct {
Date time.Time
Total int
}
db.Model(&User{}).Select("name, sum(age) as total").Where("name LIKE ?", "group%").Group("name").First(&result)
// SELECT name, sum(age) as total FROM `users` WHERE name LIKE "group%" GROUP BY `name` LIMIT 1 db.Model(&User{}).Select("name, sum(age) as total").Group("name").Having("name = ?", "group").Find(&result)
// SELECT name, sum(age) as total FROM `users` GROUP BY `name` HAVING name = "group"
// 智能选择字段
type APIUser struct {
Name string
Total int
}
rows, err := db.Debug().Table("users").Select("name, sum(age) as total").Group("name").Having("total > ?", 11).Rows()
// SELECT name, sum(age) as total FROM `users` GROUP BY `name` HAVING total > 11
for rows.Next() {
var users APIUser
db.ScanRows(rows, &users)
myPrint(users)
}
/*
type: main.APIUser value: {老王 65}
type: main.APIUser value: {马亚南 12}
*/
type Result struct { Date time.Time Total int64 } db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)

  

Distinct

db.Debug().Distinct("date", "total").Order("total desc, date desc").Find(&results)
// SELECT DISTINCT `date`,`total` FROM `results` ORDER BY total desc, date desc

  

Joins

db.Debug().Model(new(User)).Select("users.name, emails.email").Joins("left join emails on users.id = emails.user_id").Scan(&results)
// SELECT users.name, emails.email FROM `users` left join emails on users.id = emails.user_id

rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
fmt.Println(rows)
}

db.Debug().Table("users").Select("users.name, emails.email").Joins("left join emails on users.id = emails.user_id").Scan(&results)
// SELECT users.name, emails.email FROM `users` left join emails on users.id = emails.user_id

// 带参数的多表连接
// 方法一
//db.Debug().Joins("JOIN users ON users.id=emails.user_id AND users.name=?", "老王").Find(&emails)
// SELECT `emails`.`user_id`,`emails`.`email` FROM `emails` JOIN users ON users.id=emails.user_id AND users.name='老王'
// 方法二
db.Debug().Joins("JOIN users ON users.id=emails.user_id").Where("users.name=?", "李四").Find(&emails)
// SELECT `emails`.`user_id`,`emails`.`email` FROM `emails` JOIN users ON users.id=emails.user_id WHERE users.name='李四'

  

Joins 预加载

  您可以使用 Joins 实现单条 SQL 预加载关联记录,例如:

Scan

  scan将结果放到结构体中的方式与Find类似

db.Debug().Table("users").Joins("left join emails on users.id=emails.user_id").Scan(&results)
// SELECT * FROM `users` left join emails on users.id=emails.user_id

// 原生SQL
db.Debug().Raw("select name, email from users inner join emails on users.id=emails.user_id where users.name=?", "李四").Scan(&results)
// select name, email from users inner join emails on users.id=emails.user_id where users.name='李四'

 

gorm中的基本查询的更多相关文章

  1. gorm中的高级查询

    智能选择字段 GORM 允许通过 Select 方法选择特定的字段,如果您在应用程序中经常使用此功能,你也可以定义一个较小的结构体,以实现调用 API 时自动选择特定的字段,例如: type User ...

  2. 详细讲述MySQL中的子查询操作 (来自脚本之家)

    继续做以下的前期准备工作: 新建一个测试数据库TestDB: ? 1 create database TestDB; 创建测试表table1和table2: ? 1 2 3 4 5 6 7 8 9 1 ...

  3. 在update语句中使用子查询

    在update 中的 where 子句中使用子查询: UPDATE mg_page_log as a  SET  page_num=1 WHERE id in( SELECT id  from mg_ ...

  4. (九)WebGIS中的矢量查询(针对AGS和GeoServer)

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 在第七章里我们知道了WebGIS中要素的本质是UICompo ...

  5. mysql中的模糊查询

    转载自:http://www.letuknowit.com/archives/90/ MySQL中实现模糊查询有2种方式:一是用LIKE/NOT LIKE,二是用REGEXP/NOT REGEXP(或 ...

  6. Hibernate中的HQL查询与缓存机制

    HQL:完全面向对象查询 SQL的执行顺序: 1.From 2.Where 过滤基础数据 where与having的区别:1.顺序不同 2.where过滤基础数据 3. 过滤聚合函数 3.Group ...

  7. 浅谈T-SQL中的子查询

    引言 这篇文章我们来简单的谈一下子查询的相关知识.子查询可以分为独立子查询和相关子查询.独立子查询不依赖于它所属的外部查询,而相关子查询则依赖于它所属的外部查询.子查询返回的值可以是标量(单值).多值 ...

  8. oracle中的连接查询与合并查询总结

    连接查询: 连接查询是指基于多张表或视图的查询.使用连接查询时,应指定有效的查询条件,不然可能会导致生成笛卡尔积.如现有部门表dept,员工表emp,以下查询因查询条件无效,而产生笛卡尔积:   (各 ...

  9. 在 SQL Server 数据库的 WHERE 语句中使用子查询

    这是关于子查询语句的一系列文章中的第三篇.在这篇文章中我们将讨论WHERE语句中的子查询语句.其他的文章讨论了其他语句中的子查询语句. 本次课程中的所有例子都是基于Microsoft SQL Serv ...

随机推荐

  1. Spring Boot应用程序启动器

    官网地址:https://docs.spring.io/spring-boot/docs/2.1.12.RELEASE/reference/html/using-boot-build-systems. ...

  2. UDP&串口调试助手用法(4)

    接收配置用法 概览 保存文件 可将数据保存到文件和文件夹 如果选择的时文件,则需要自己手动选择保存的文件. 如果选择的时文件夹,则需要指定文件夹的类型和文件的后缀 支持保存文件类型: 文本文件和二进制 ...

  3. 【LeetCode】1023. Camelcase Matching 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 正则+字典 日期 题目地址:https://leet ...

  4. 【LeetCode】215. Kth Largest Element in an Array 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:移除最大值 方法二:排序 方法三:大顶堆 方 ...

  5. 【LeetCode】399. Evaluate Division 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. 1120 机器人走方格 V3

    1120 机器人走方格 V3 基准时间限制:1 秒 空间限制:131072 KB N * N的方格,从左上到右下画一条线.一个机器人从左上走到右下,只能向右或向下走.并要求只能在这条线的上面或下面走, ...

  7. 版本不兼容Jar包冲突该如何是好?

    一.引言 "老婆"和"妈妈"同时掉进水里,先救谁? 常言道:编码五分钟,解冲突两小时.作为Java开发来说,第一眼见到ClassNotFoundExceptio ...

  8. 第九届河南理工大学算法程序设计大赛 正式赛L:最优规划(最小生成树)

    单测试点时限: 1.0 秒 内存限制: 512 MB 有很多城市之间已经建立了路径,但是有些城市之间没有路径联通.为了联通所有的城市,现在需要添加一些路径,为了节约,需要满足添加总路径是最短的. 输入 ...

  9. 【Java例题】5.2 数组转换

    2. 有一个一维数组由键盘输入,据输入的m和n,将其转换为m*n的二维数组. package chapter5; import java.util.Scanner; public class demo ...

  10. [opencv]拟合vector<Mat>集合区域接近的元素

    vector<Rect> PublicCardFrameDetection::fitrect(vector<Rect> rects){ int size = rects.siz ...