GORM---高级查询

news2025/4/10 14:32:56

文章目录

  • 构建Demo数据
    • 模型定义
    • 数据表
  • 高级查询
    • 子查询
    • 选择字段
    • 排序
    • 数量
    • 偏移
    • 总数
    • Group & Having
    • 连接
  • Pluck
  • 扫描

构建Demo数据

模型定义

type Users struct {
	Id      uint64 `gorm:"primary_key;NOT NULL"`
	EmailId uint64 `gorm:"foreignKey:email_id;references:Email;"`
	Email   Email  `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL"`
	Age     uint64
	Name    string
}

type Email struct {
	EmailId uint64 `gorm:"column:email_id;primary_key;NOT NULL"`
	Addr    string
}

数据表

Users表:

image-20230606160807983

Email表:

image-20230606160853851

高级查询

子查询

子查询是指一个查询语句嵌套在另一个查询语句内部的查询,内部的查询是外部查询的条件。

//查询大于平均年龄的所有记录
var u1 []*connect.Users
connect.DB.Where("age > (?)", connect.DB.Table("users").Select("AVG(age)")).Find(&u1)
//SELECT * FROM `users` WHERE age > (SELECT AVG(age) FROM `users`)
for _, v := range u1 {
    fmt.Printf("%+v\n", v)
}

运行结果如下:

image-20230606165433813

由于平均年龄需要计算,所以内层的SELECT语句的作用是为了得到平均年龄(connect.DB.Table(“users”).Select(“AVG(age)”)),外层的SELECT语句的作用就是条件判断。

var u2 []*connect.Users
subQuery := connect.DB.Select("AVG(age)").Where("name LIKE ?", "%y%").Table("users")
connect.DB.Select("name,AVG(age) as avgAge").Group("name").Having("AVG(age) > (?)", subQuery).Find(&u2)
//SELECT name,AVG(age) as avgAge FROM `users` GROUP BY `name` HAVING AVG(age) > (SELECT AVG(age) FROM `users` WHERE name LIKE '%y%')
for _, v := range u2 {
    fmt.Printf("%+v\n", v.Name)
}

运行结果如下:

image-20230606185017226

虽然这个子查询的例子的实际意义不大,但实在是想不出什么好的例子了。首先subQuery变量存储的是内层SELECT语句的查询结果,就是查询在users表中查找name字段类似于%y%的(中间有y的name字段)的记录,并计算这些记录的平均年龄(24+23+25+25+23)/5=24。接下来就外层SELECT语句的作用就是:根据name指定分组(共四组:abc、xyz、dyg、xyg),找出这四组中的年龄大于24的记录。不熟悉group having的详见:mysql必知必会——GROUP BY和HAVING

选择字段

Select方法能指定你想从数据库中检索出的字段,默认会选择全部字段。

var u1, u2 []*connect.Users
connect.DB.Select("name, age").Find(&u1) //写法一 
//SELECT `name`,`age` FROM `users`
connect.DB.Select([]string{"name", "age"}).Find(&u2) //写法二
//SELECT `name`,`age` FROM `users`

//例二
var age int
rows, err := connect.DB.Table("users").Select("COALESCE(age,?)", 0).Rows()
	//SELECT COALESCE(age,23) FROM `users`
	if err != nil {
		fmt.Println(err.Error())
	}
	defer rows.Close()

	for rows.Next() {
		if err = rows.Scan(&age); err != nil {
            fmt.Println(err.Error())
		}
		fmt.Println(age)
	}

例二的代码分析如下:

  1. 使用 Table() 方法指定要查询的数据表为 users。
  2. 使用 Select() 方法指定查询的字段为 COALESCE(age,?),其中 COALESCE() 函数是一个条件判断函数,如果 age 不为 NULL,则返回 age 的值,否则返回指定的值,这里指定的值是 ?,这代表一个占位符,会在执行查询语句时被具体的值替换,这里占位符的值为 0。
  3. 使用 Rows() 方法执行查询并返回结果集,该方法会返回一个 *sql.Rows 对象,表示整个结果集。
  4. 使用 rows 变量可以遍历结果集,处理每一行数据。

排序

Order,指定从数据库中检索出记录的顺序。

var u1, u2 []*connect.Users
connect.DB.Order("age desc, name").Find(&u1)
// SELECT * FROM users ORDER BY age desc, name;
for _, v := range u1 {
    fmt.Printf("%+v\n", v)
}

// 多字段排序
connect.DB.Order("age desc").Order("name").Find(&u2)
// SELECT * FROM users ORDER BY age desc, name;
for _, v := range u2 {
    fmt.Printf("%+v\n", v)
}

数量

Limit,指定从数据库检索出的最大记录数。

var u1, u2, u3 []*connect.Users
connect.DB.Limit(3).Find(&u1)
//SELECT * FROM `users` LIMIT 3 (u1)

// -1 取消 Limit 条件
connect.DB.Limit(5).Find(&u2).Limit(-1).Find(&u3)
//SELECT * FROM `users` LIMIT 5 (u2)
//SELECT * FROM `users` (u3)

偏移

Offset,指定开始返回记录前要跳过的记录数。需要注意的是,在mysql中OFFSET关键字必须要与LIMIT关键字搭配使用。

var u1, u2, u3 []connect.Users
connect.DB.Limit(3).Offset(3).Find(&u1)
//SELECT * FROM `users` LIMIT 5 OFFSET 3
for _, v := range u1 {
    fmt.Printf("%+v\n", v)
}

connect.DB.Limit(3).Offset(2).Find(&u2).Offset(-1).Find(&u3)
//SELECT * FROM `users` LIMIT 2 OFFSET 2 (u2)
//SELECT * FROM `users` LIMIT 2 (u3)
for _, v := range u2 {
    fmt.Printf("%+v\n", v)
}
fmt.Println()
for _, v := range u3 {
    fmt.Printf("%+v\n", v)
}

运行结果如下:

image-20230607101939068

image-20230607102048610

总数

Count,该 model 能获取的记录总数。

var u []connect.Users
var count1, count2, count3 int64
connect.DB.Where("name = ?", "xyg").Or("name = ?", "dyg").Find(&u).Count(&count1)
//SELECT * FROM `users` WHERE name = 'xyg' OR name = 'dyg'
//SELECT count(*) FROM `users` WHERE name = 'xyg' OR name = 'dyg'

connect.DB.Model(&connect.Users{}).Where("name = ?", "abc").Count(&count2)
//SELECT count(*) FROM `users` WHERE name = 'abc'

connect.DB.Table("email").Select("count(distinct(addr))").Count(&count3)
//SELECT count(distinct(addr)) FROM `email`

注意 Count 必须是链式查询的最后一个操作 ,因为它会覆盖前面的 SELECT,但如果里面使用了 count 时不会覆盖。

Group & Having

详见子查询。

连接

Joins,指定连接条件。

//SELECT users.name, email.addr FROM `users` left join email on email.email_id = users.email_id
rows, err := connect.DB.Table("users").Select("users.name, email.addr").Joins("left join email on email.email_id = users.email_id").Rows()
	if err != nil {
		fmt.Println(err)
	}
	type Result struct {
		Name string
		Addr string
	}
	var r Result
	for rows.Next() {

		if err = rows.Scan(&r.Name, &r.Addr); err != nil {
			fmt.Println(err.Error())
		}
		fmt.Println(r)
	}

运行结果如下:

image-20230607111622176

Pluck

Pluck,查询 model 中的一个列作为切片。

var ages []int64
connect.DB.Table("users").Pluck("age", &ages)
fmt.Println(ages)

运行结果如下:

image-20230607113920199

扫描

Scan用来扫描结果至一个 struct。

type Result struct {
		Name string
		Age  int
	}

	var result1, result2 Result
	var results []Result
	connect.DB.Table("users").Select("name, age").Where("name = ?", "xyg").Scan(&result1)
	//SELECT name, age FROM `users` WHERE name = 'xyg'
	fmt.Println(result1)

	connect.DB.Table("users").Select("name, age").Where("id > ?", 0).Scan(&results)
	//SELECT name, age FROM `users` WHERE id > 0
	fmt.Println(results)
	// 原生 SQL
	connect.DB.Raw("SELECT name, age FROM users WHERE name = ?", "xyg").Scan(&result2)
	//SELECT name, age FROM users WHERE name = 'xyg'
	fmt.Println(result2)

image-20230607122827224

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/642837.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python + pytest 接口自动化 —— 参数关联

什么是参数关联? 参数关联,也叫接口关联,即接口之间存在参数的联系或依赖。在完成某一功能业务时,有时需要按顺序请求多个接口,此时在某些接口之间可能会存在关联关系。 比如:B接口的某个或某些请求参数是…

高级数据结构-线段树

线段树 线段树树基于分治思想的二叉树,用来维护区间信息(区间和、区间最大值、区间最小值等等)。可以在 O ( l o g n ) O(logn) O(logn)的时间内完成区间信息的查询和修改。 线段树中每个叶子结点存储元素本身,非叶子结点存储区间内元素的统计值 节点数组…

C#多线程Task常见问题(二)

1 多线程临时变量 2 线程安全和锁lock 3 线程安全策略总结 线程安全和锁lock 线程安全问题:一段程序逻辑在单线程中执行和多线程中执行,结果一致说明线程是安全的;如果结果不同说明线程不安全。 同样先看一个例子:分别用主线程…

唯品会宕机惨案,损失超亿元!故障来时如何迅速应对?

01 事件回顾 对于IT工程师来说,宕机并非新鲜话题,经历过一次服务器宕机,职业生涯才“完整”。但如果事故超过 12 小时,或许会直接造成职业生涯“宕机”。 3月29日发生的突发事件,#唯品会App崩了 冲上热搜&#xff0…

最全整理,完整一套WEB/APP/接口测试测试流程,全面覆盖...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 web测试流程 需求…

Java --- springboot3整合redis

目录​​​​​​​ 一、整合redis 1.1、导入pom依赖 1.2、修改springboot配置文件 1.3、代码测试 二、测试访问redis五大常用数据类型 三、自动配置原理 四、定制化 4.1、解决redis存储序列化乱码问题 4.2、redis客户端使用jedis 一、整合redis 1.1、导入pom依赖 …

【考试】2023年5月软件设计师考试感受

前言❤️ 由于考试地点距离住的地方很远,一个南面一个北面,所以BZ选择了提前一天去到考试地点附近,住在考点附近。吃了晚饭后。到住的地方大概9点多,洗漱完,10点左右开始考前过知识点,复习到凌晨3点左右。…

改进的粒子滤波算法及其应用研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

【博客660】prometheus默认5min的lookback机制带来查询的影响

prometheus默认5min的lookback机制带来查询的影响 1、prometheus staleness机制 我发过的:【博客616】prometheus staleness对PromQL查询的影响 官方staleness解析 相关文章:do-prometheus-metrics-have-some-sort-of-freshness-lifetime 相关issue…

全面解析数据治理

摘要 数据治理并不是一种简单的操作行为,而是对数据资产管理行使权力和控制的活动集合,是一种管理和保护数据的方法,是确保准确性、完整性、安全性、可靠性和一致性的关键。 通过数据治理,企业可以更好地掌握现有数据&#xff0…

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

文章目录 前言🌟一、为什么存在动态内存分配🌟二、动态内存函数的介绍🌏2.1.malloc函数free函数🌏2.2.calloc函数free函数🌏2.3.realloc函数 🌟三、常见的动态内存错误🌏3.1.对NULL指针的解引用…

SQL(--修改中--)

目录 一、基本介绍 二、常用函数 集合函数 字符串函数 MYSQL的日期和时间函数 SQL重要的内建日期函数 MYSQL重要的内建日期函数 条件判断函数 三、操作 单表查询 多表查询 使用正则表达式查询 添加: 修改: 删除: 四、…

Linux系统实现虚拟内存教程

Linux系统实现虚拟内存有两种方法:交换分区(swap分区)和交换文件, 一、交换文件 查看内存:free -m , -m是显示单位为MB,-g单位GB free -g 创建一个文件:touch命令用于修改…

【2023电工杯】A题 电采暖负荷参与电力系统功率调节的技术经济分析 30页论文及python代码

【2023电工杯】A题 电采暖负荷参与电力系统功率调节的技术经济分析 30页论文及python代码 1 题目 A题:电采暖负荷参与电力系统功率调节的技术经济分析 建设以新能源为主体的新型电力系统是应对全球气候变化挑战的重要举措。高比例新能源接入导致电力系统调节能力稀缺&#x…

电厂人员定位管理系统,厂区人员及车辆轨迹可循

随着科技的不断发展,室内定位技术已经逐渐成为电厂管理中不可或缺的一部分。在传统的变电站管理中,由于缺乏有效的定位技术,很难对设备、人员和物资进行精确的管理,导致了效率低下、成本高昂的问题。而现在,通过引入室…

企业必须知道:数字化官网已成为新发展格局

​如今我们生活在一个数据驱动发展的时代,不能顺应时代发展进步的企业就会落后和淘汰。一个新技术时代应运而生,一个数据主导的数字企业时代也必将应声而至。 社交媒体、移动设备、物联网和大数据引发的数字化趋势不仅改变了人们的生活方式而且要求企业…

工厂模式(四)

过气的,终究是过气了 上一章简单介绍了单例模式(三), 如果没有看过,请观看上一章 一. 工厂模式 引用 菜鸟教程里面的单例模式介绍: https://www.runoob.com/design-pattern/factory-pattern.html 工厂模式(Factory Pattern)是 Java 中最常…

输电线路可视化监拍装置硬件解决方案

老旧输电线路可视化监控装置 随着我国人口的增长,电力设施的规模也变得越发庞大,人工运检的负担也越来越沉重,而且巡检的时效性也是痛点,于是电网提出智慧可视化管理通道运检的方案,线路在线监测装置成为其基础&#x…

前端开发环境部署问题(高级程序员必备)

很多开发者到了一家新公司,公司发了一台新电脑,对环境安装比较困惑。今天带大家还原,拿到公司电脑,如何安装你需要的各种环境。 一、node安装 官网下载地址: http://nodejs.cn/download/ 根据自己需要下载对应的版…

电脑多久重装一次系统比较好

在长时间使用电脑后,一些用户可能会考虑重装系统来提升性能和稳定性。然而,电脑重装系统的频率是一个有争议的问题。本文将探讨电脑重装系统的最佳频率,以帮助您做出明智的决策。 工具/原料: 系统版本:win7旗舰版 品…