MySQL表的增删改查

  • 在进行表操作之前,一定要use选中数据库

  • 注释:在SQL中可以使用 --空格+描述 来表示注释说明

  • CRUD 即增加(Create)、查询(Retrieve)、更新(Update)、删除(Delete)四个单词的首字母。

文章目录

数据库约束

数据库约束可以理解成数据库提供的一种针对 数据合法性 验证的机制

约束类型

  • NOT NULL - 指示某列不能存储 NULL 值,表里的内容是必填项
  • UNIQUE - 保证某列的每行必须是唯一的值(不能重复),每次插入/修改都会先触发查询,如果值已经存在,就会插入/修改失败
  • DEFAULT - 指定没有被赋值的列的默认值。不进行任何指定,默认值就是NULL
  • PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。(相当于一条记录的身份标识)
  • FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • CHECK - 保证列中的值符合指定的条件。MySQL数据库对CHECK子句进行分析,但是忽略CHECK子句。也就是不会报错,但是也不会生效。check指定条件,插入/修改数据时数据符合条件才能插入/修改成功;不符合条件则失败

NOT NULL约束

指定某列不为空:

UNIQUE:唯一约束

指定列的内容唯一的、不重复的:

DEFAULT:默认值约束

指定不插入数据时的默认值:

PRIMARY KEY:主键约束

  • 不能为null
  • 不能重复

相当于NOT NULL 和 UNIQUE 的结合

指定id列为主键:

一般给表设定主键使用数字(整数形式),很少使用字符串.

  • 一个表只能有一个主键

  • 一个主键不一定只针对一个列(联合主键----把多个列的内容联合到一起,共同构成一个主键),很少使用这个功能

  • 当某个列集合了 not nullunique 就成为主键了

一般使用整数 id 作为主键,但id的值该如何选择呢?

MySQL提供了"自增主键", 对于整数类型的主键,常配搭自增长auto_increment来使用。插入数据对应字段不给值时,赋值为最大值+1。

  • auto:自动
  • increment:增加

此时插入数据,主键的值就不用手动指定了

当然还可以手动指定,不一定依赖自增主键

如果把 id = 100 和 id = 101 删去,按理来说是从102开始自增,但不知道为啥我的会跳号

4~102这一批id,如果不手动指定就浪费了,如果不想浪费可以不依赖自动增键主动添加

自增主键本质 是MySQL服务器存储了当前表中最大的id,再进一步进行累加的。基于分布式系统存储数据的时候,MySQL自增主键就无能为力了.

在分布式系统中,如何生成唯一id?

最简单最朴素的方式: 时间戳 + 机器编号 + 随机数

再计算哈希值得到一个整数,这个整数可以作为id
简单介绍用md5计算hash值的特性

  • 定长. 无论输入的字符串多长,最终计算的hash值都是一样长的(作为校验和的一种方式)
  • 分散. 输入的字符串,哪怕只有一点点不一样,得到的 hash值 都会差异很大(成为hash 算法的根本)
  • 不可逆. 计算出的hash值理论上无法还原成原来的字符串(可以作为一种加密手段)

FOREIGN KEY:外键约束

外键用于关联其他表的主键或唯一键,语法:

sql 复制代码
foreign key (字段名) references 主表(列)

案例:

插入 student 表的classId 必须要在 class 表的classId中存在,插入的学生才有意义(从属于某个班级)

此时,外键就让student 的 classId 就和 class 表的 classId 建立了联系.也就是student classId 中的值,必须要在 class 表的 classId 中存在. class 表就对 student 表产生了制约

  • 父表中被引用的列必须是主键或是 unique
  • 把 class 表(制约别人的表) 称为"父表"(parent table)
  • 把 student 表(被制约的表) 称为"子表"(child table)

父表可以删除/修改没有被子表引用的记录,但如果被引用了就不能删除/修改了.

子表不能随意插入/修改(外键必须在父表中)

CHECK约束(了解)

MySQL使用时不报错,但忽略该约束:

sql 复制代码
drop table if exists test_user;
create table test_user (
   id int,
   name varchar(20),
   sex varchar(1),
   check (sex ='男' or sex='女')
);

新增(Create)

全列插入

sql 复制代码
insert into 表名 values (值, 值...);
  • 可以省略into
  • values是关键字

一次插入多行记录

sql 复制代码
insert into 表名 values(值, 值...), (值, 值...), (值, 值...)...;

一次插入多条记录往往比一次插入一条记录,分多次插入的效率要高

MySQL是客户端 - 服务器结构的程序

客户端中执行的每个操作,都会通过网络请求发送给服务器,而服务器返回一个响应内容

虽然请求中包含了更多的数据,但网络开销更小了.网络开销对效率的影响大

指定列插入

sql 复制代码
insert into 表名(列名, 列名...) values(值, 值...);

列名个数和顺序无需和表头信息一致,只需保证列名是存在的

插入时间


'2024-04-22 11:13:00'是一个标准的时间格式化写法

有时,插入的数据要指定当前系统的时间,MySQL有一个专门的函数now()来获取

插入查询结果(不用values关键字)

需要确保查询到的结果集合(列数/类型/顺序),要和待插入表的列数/类型/顺序匹配

语法:

sql 复制代码
INSERT INTO 表名 [列名,列名...] SELECT ...;

SQL是"弱类型"的编程语言,和Java这种"强类型"的编程语言是不一样的

  • 强类型和弱类型的区别:是否支持隐式类型转换
  • 静态类型和动态类型的区别: 一个变量的类型,能否在程序运行过程中发生改变,不允许改变的是静态类型,允许改变的就是动态类型. C,Java属于静态类型; Python,JS属于动态类型
  • SQL一般不会谈到变量这个概念
  • SQL隐式类型转换

    '100' 转换成 100
    2 转换成 '2'
  • Java显示类型转换

1.整型转字符串

2.字符串转整型

一个编程语言,越支持"隐式类型转换",类型系统就越弱.越不支持"隐式类型转换", 类型系统就越强

查询(Retrieve)

查询的所有操作都不会影响数据库服务器硬盘上存储的数据

全列查询

sql 复制代码
select * from 表名;

能够查询出表中所有行和列

sql 复制代码
-- 通常情况下不建议使用 * 进行全列查询
-- 1. 查询的列越多,意味着需要传输的数据量越大;
-- 2. 可能会影响到索引的使用。

指定列查询

sql 复制代码
select 列名, 列名... from 表名;

确保列名是存在合法的

列的顺序不需要按定义表的顺序来

查询字段为表达式

查询的结果不仅仅是列,而是把列代入到表达式中进行运算的结果

表达式查询,只是针对服务器响应得到的临时结果进行计算,不影响服务器硬盘上存储的数据本体
SQL中进行算术运算的时候,如果其中某个操作数是NULL,最后的计算结果也就是NULL了

sql 复制代码
-- 表达式不包含字段
SELECT id, name, 10 FROM exam_result;
-- 表达式包含一个字段
SELECT id, name, english + 10 FROM exam_result;
-- 表达式包含多个字段
SELECT id, name, chinese + math + english FROM exam_result;

别名

为查询结果中的列指定别名,表示返回的结果集中,以别名作为该列的名称,语法:

sql 复制代码
SELECT 列名 [AS] 别名 FROM 表名;

AS可以省略,但可读性变差了很多,所以不推荐

去重:DISTINCT

针对查询结果进行去重,如果存在重复数据,就会把重复的行合并成一行(如果查询包含多列,那么那几列都要相同才算重复)

使用DISTINCT关键字对某列数据进行去重:

sql 复制代码
select distinct 列名 from 表名;

排序:ORDER BY

  1. 没有 ORDER BY 子句的查询,返回的顺序是未定义的
  2. NULL 视为比任何值都小,升序出现在最上面,降序出现在最下面.如果存在多个NULL,多个NULL之间的顺序是不确定的
  3. ORDER BY默认是按照升序排序(ASC),如果要降序排序,需要加上DESC关键字
  4. 排序是以 行 为单位进行排序的

不同desc

desc 表名 是describe的缩写

order by 的 desc 是 descend的缩写

语法:

sql 复制代码
-- ASC 为升序(从小到大)
-- DESC 为降序(从大到小)
-- 默认为 ASC
SELECT ... FROM 表名 [WHERE ...] ORDER BY 列名/表达式 [ASC|DESC];

order by 后面写的列名/表达式不一定要在select后面的列名/表达式里出现

使用表达式及别名排序

sql 复制代码
-- 查询同学及总分,由高到低
SELECT name, chinese + english + math FROM exam_result ORDER BY chinese + english + math DESC;
SELECT name, chinese + english + math as total FROM exam_result ORDER BY total DESC;
  1. 可以对多个字段进行排序,排序优先级随书写顺序
sql 复制代码
SELECT ... FROM 表名 [WHERE ...] ORDER BY 列名/表达式 [ASC|DESC], 列名/表达式 [ASC|DESC]...;

先按照order by后面的第一列排序,再是第二列,第三列...

sql 复制代码
-- 查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示
SELECT name, math, english, chinese FROM exam_result ORDER BY math DESC, english, chinese;

条件查询:WHERE

NULL和其他值进行关系运算的结果也是NULL,NULL在SQL中可以隐式转成FALSE

sql 复制代码
SELECT ... FROM 表名 [WHERE ...]

比较运算符:

运算符 说明
>, >=, <, <= 大于,大于等于,小于,小于等于
= 比较相等,NULL 不安全,例如 NULL = NULL 的结果是 FALSE
<=> 比较相等,NULL 安全,例如 NULL <=> NULL 的结果是 TRUE(1)
!=, <> 不等于
BETWEEN a0 AND a1 范围匹配,如果 a0 <= value <= a1,返回 TRUE(1),注意是闭区间
IN (option, ...) 如果是 option 中的任意一个,返回 TRUE(1)
IS NULL 是 NULL
IS NOT NULL 不是 NULL
LIKE 模糊匹配。% 表示任意多个(包括 0 个)字符; _ 表示任意一个字符
  • BETWEEN a0 AND a1描述的是"连续的区间"
  • IN (option, ...)描述的是"离散的集合"
  • = 是精确查询,要求查询出的结果和条件中指定的内容完全一致
  • like是模糊查询,只要有一部分一致即可, 比如'孙%'匹配孙开头的内容。 这样的操作开销很大,性能很低,慎用
sql 复制代码
-- % 匹配任意多个(包括 0 个)字符
SELECT name FROM exam_result WHERE name LIKE '孙%';-- 匹配到孙悟空、孙权
-- _ 匹配严格的一个任意字符
SELECT name FROM exam_result WHERE name LIKE '孙_';-- 匹配到孙权

逻辑运算符:

运算符 说明
AND 多个条件必须都为 TRUE(1),结果才是 TRUE(1)
OR 任意一个条件为 TRUE(1), 结果为 TRUE(1)
NOT 条件为 TRUE(1),结果为 FALSE(0);条件为FALSE(0),结果为 TRUE(1)

注:

  1. WHERE条件可以使用表达式,但不能使用别名。

查询的执行顺序:

1.遍历表

2.代入条件

3.计算列名中的表达式(定义别名)

4.排序/聚合等操作

所以执行where在定义别名前面

  1. AND的优先级高于OR,在同时使用时,需要使用()包裹优先执行的部分

分页查询:LIMIT

  • limit关键字用来描述本次查询最多返回多少条记录
  • 搭配offset关键字,offset称为偏移量(相当于下标), 不写offset就相当于offset 0.

假定一页显示 10条记录

第一页: limit 10 offset 0

第二页: limit 10 offset 10

...

如果结果不足10个不影响

语法:

sql 复制代码
-- 起始下标为 0
-- 从 0 开始,筛选 n 条结果
SELECT ... FROM 表名 [WHERE ...] [ORDER BY ...] LIMIT n;
-- 从 s 开始,筛选 n 条结果
SELECT ... FROM 表名 [WHERE ...] [ORDER BY ...] LIMIT s, n;
-- 从 s 开始,筛选 n 条结果,比第二种用法更明确,建议使用
SELECT ... FROM 表名 [WHERE ...] [ORDER BY ...] LIMIT n OFFSET s;

聚合查询(行与行之间的运算)

聚合函数

  • 遇到NULL就会跳过
  • 聚合函数的函数名和括号之间,不能有空格

常见的统计总数、计算平均值等操作,可以使用聚合函数来实现,常见的聚合函数有:

函数 说明
COUNT([DISTINCT] expr) 返回查询到的数据的 数量
SUM([DISTINCT] expr) 返回查询到的数据的 总和,不是数字没有意义
AVG([DISTINCT] expr) 返回查询到的数据的 平均值,不是数字没有意义
MAX([DISTINCT] expr) 返回查询到的数据的 最大值,不是数字没有意义
MIN([DISTINCT] expr) 返回查询到的数据的 最小值,不是数字没有意义
  • COUNT

只有count的参数能是 * ,count(*) 相当于 先执行 select * from 表名 再对结果进行 count 聚合

*也可以换成具体的列名/表达式,如果写成具体的列名/表达式,就是针对这一列/表达式查询,再进行聚合

sql 复制代码
-- 统计班级共有多少同学
SELECT COUNT(*) FROM student;
SELECT COUNT(0) FROM student;
-- 统计班级收集的 qq_mail 有多少个,qq_mail 为 NULL 的数据不会计入结果
SELECT COUNT(qq_mail) FROM student;

1)可以帮我们获取到非空记录的数量

2)可以搭配 group by 进行分组

  • SUM
sql 复制代码
-- 统计数学成绩总和
SELECT SUM(math) FROM exam_result;
-- 统计数学成绩 < 60 的总和,如果没有结果,返回 NULL
SELECT SUM(math) FROM exam_result WHERE math < 60;
  • AVG
sql 复制代码
-- 统计平均分数
SELECT AVG(chinese + math + english) as 平均总分 FROM exam_result;
  • MAX
sql 复制代码
-- 返回英语最高分
SELECT MAX(english) FROM exam_result;
  • MIN
sql 复制代码
-- 返回 > 70 分以上的数学最低分
SELECT MIN(math) FROM exam_result WHERE math > 70;

分组查询: GROUP BY子句

SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。使用 GROUP BY 进行分组查询时,SELECT 指定的字段必须是"分组依据字段",其他字段若想出现在SELECT 后必须包含在聚合函数中,不然没有意义。

sql 复制代码
select column1, sum(column2), .. from 表名 group by column1,column3;

案例

1.先执行 select role, id from emp

2.再根据group by role,按照 role 这一列的值针对上述查询结果进行分组

3.针对上述的每个组,分别执行 count 聚合操作,结果整理成临时表(这几个分组的顺序谁先谁后是不确定的),返回给客户端

还可以进行排序:

是可以针对聚合后的结果进行排序,而不是干预每个分组中数据的先后顺序

反例:

每个显示的结果都是每个分组中的其中一条记录,但是分组之后顺序都是不确定的,上述结果存在一定的"随机性",因此没有意义.

group by 的列,不应该直接写到 select 查询的列中(得搭配聚合函数)

给聚合查询指定条件

聚合之前的条件(WHERE 在 group by 之前)

举例:

查询每个岗位的平均工资,但是刨除"张三"

聚合之后的条件(HAVING 在 group by 之后)

GROUP BY 子句进行分组以后,需要对分组结果再进行条件过滤时,不能使用 WHERE 语句,而需要用HAVING
举例:

查询每个岗位的平均工资,但是刨除平均工资超过1万的岗位(计算出每个岗位的平均工资之后才能进行上述条件筛选)

联合查询(多表查询)

实际开发中往往数据来自不同的表,所以需要多表联合查询。多表查询是对多张表的数据取笛卡尔积(多表查询的基础):

列数就是原来的两个表的列数之和

行数就是原来两个表的行数之积

注意:联合查询可以对关联表使用别名。

多表联合查询的一般步骤

  1. 确定要查的信息来自哪几个表
  2. 把这些表进行笛卡尔积
  3. 指定连接条件
  4. 指定其他补充条件/聚合操作
  5. 针对列进行精简

内连接

语法:

sql 复制代码
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;

在SQL中, 可以很方便地通过 select 完成笛卡尔积

上述笛卡尔积中存在一部分无效/无意义的数据,如果数据不能反映客观的真实情况,这个数据就是无效的

在写条件的时候,给列名前面显式加上表名即可

如果class 的classId 改名为 class_id,这个时候前面不加表名.也行,但还是建议加上,有助于提高可读性

还有join on的写法

指定连接条件

外连接

外连接和内连接一样也是基于笛卡尔积的方式来计算,但对于空值/不存在的值,处理方式存在区别。

外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接。

在两张表的数据"一 一对应"的情况下,内连接和外连接的结果是一样的

如果不能"一 一对应",内连接和外连接的结果就有所不同了

  • 孙七的classId在 class 表中不存在
  • class 表中 java104 在 student表中也不存在

对上述数据进行内连接,得到的结果就是只包含两个表都存在的数据

inner可以省略

外连接语法:

sql 复制代码
-- 左外连接,表1完全显示
select 列名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显示
select 列名 from 表名1 right join 表名2 on 连接条件;

左外连接会保证左侧表的每个数据都会存在,左侧表数据在右侧表不存在的部分会使用NULL表示

右外连接和左外连接类似,以右表为基准,使右表中的每个数据都存在,对应左表不存在的部分用NULL填充

自连接

自连接是指在同一张表连接自身进行查询。(自己和自己进行笛卡尔积)
案例:

显示所有"数据库"成绩比"数据结构"成绩高的成绩信息

直接进行自连接发现不行

要给表起别名

自连接能把行之间的关系转换成列之间的关系

子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

  • 单行子查询:返回一行记录的子查询
sql 复制代码
select ... from 表1 where 字段1 = (select ... from ...);

查询'张三'的同班同学:

  • 多行子查询:返回多行记录的子查询

案例:查询"数据结构"或"Java"课程的成绩信息

1. [NOT] IN关键字:

语法:

sql 复制代码
 select ... from 表1 where 字段1 in (select ... from ...);

in

not in

2. [NOT] EXISTS关键字 (比 IN 效率低,但节省内存):

语法:

sql 复制代码
select ... from 表1 where exists (select ... from ... where 条件);

使用 EXISTS

使用 NOT EXISTS

  • 在from子句中使用子查询:子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。
sql 复制代码
select ... from 表1, (select ... from ...) as 临时表名 where 条件

查询所有比"数据库"平均分高的成绩信息:

第一步: 获取"数据库"的平均分,将其看作临时表

第二步:查询成绩表中,比以上临时表平均分高的成绩:

合并查询

在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。使用UNION和UNION ALL时,前后查询的结果集中,列的类型/个数/顺序需要一致, 列名无所谓。

  • union(去除重复数据)
sql 复制代码
select ... from ... where 条件
union
select ... from ... where 条件

该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。

案例:查询3班或者1班的人:

相比于 or , union 可以从多个表分别查询

  • union all (不去重)
sql 复制代码
select ... from ... where 条件
union all 
select ... from ... where 条件

该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。

修改(Update)

会修改服务器硬盘上存储的数据

语法:

sql 复制代码
UPDATE 表名 SET 列名 = 值  [WHERE ...] [ORDER BY ...] [LIMIT ...]

也可以一次修改多个列,set后面写多组列,分别进行赋值即可

sql 复制代码
UPDATE 表名 SET 列名 = 值, 列名 = 值... [WHERE ...] [ORDER BY ...] [LIMIT ...]

修改也可以用表达式

此处不能写作 id += 10

删除(Delete)

删除是以 行 为维度进行删除的,删除的就是条件满足的数据.如果不指定条件,就是删除表中所有数据,不过删完全部数据之后表还是存在的,只不过是空的

语法:

sql 复制代码
DELETE FROM  表名 [WHERE ...] [ORDER BY ...] [LIMIT ...]

PS

SQL查询中各个关键字的执行先后顺序: from > on> join > where > group by > with > having >

select > distinct > order by > limit

相关推荐
微服务 spring cloud19 分钟前
配置PostgreSQL用于集成测试的步骤
数据库·postgresql·集成测试
先睡21 分钟前
MySQL的架构设计和设计模式
数据库·mysql·设计模式
弗罗里达老大爷23 分钟前
Redis
数据库·redis·缓存
仰望大佬0071 小时前
Avalonia实例实战五:Carousel自动轮播图
数据库·microsoft·c#
学不透java不改名1 小时前
sqlalchemy连接dm8 get_columns BIGINT VARCHAR字段不显示
数据库
一只路过的猫咪1 小时前
thinkphp6使用MongoDB多个数据,聚合查询的坑
数据库·mongodb
呼啦啦啦啦啦啦啦啦2 小时前
【MySQL篇】事务的认识以及四大特性
数据库·mysql
van叶~2 小时前
探索未来编程:仓颉语言的优雅设计与无限可能
android·java·数据库·仓颉
溟洵4 小时前
Linux下学【MySQL】表中插入和查询的进阶操作(配实操图和SQL语句通俗易懂)
linux·运维·数据库·后端·sql·mysql