MySQL表的增删改查进阶版

Mysql

1、数据库的约束

1.1约束类型

什么是约束?

约束是数据库自动对数据进行合法性校验检查的一系列机制 ,目的是为了数据库中能避免被插入/修改一些非法的数据,数据库引入约束后执行效率会受影响,效率会降低很多

  • NOT NULL:知识某列不能存储NULL值
  • UNIQUE :保证某列的每行必须有唯一的值,unique会让后续插入/修改数据时都先触发一次查询操作,确定当前记录是否存在
  • DEFAULT:规定没有给列赋值时的默认值
  • PRIMARY KEY:NOT NULL和UNIQUE的结合,确保某列有唯一标识,有助于更快速地找到表中的一个特定的记录,一张表中只能有一个primary key
  • FOREIGN KEY:保证一个表中数据匹配另一个表中的值的参照完整性
  • CHECK:保证列中的值符合指定的条件

下面我们来进行逐一解释

1.2 NULL约束

创建表时,可以指定某列不为空

sql 复制代码
mysql> create table student
(id int not null,sn int,name varchar(20),qq_mail varchar(20));
-- 如果id列插入null类型的数据,则会报错
mysql> insert into student values(null,1,'lisi','ddd');
ERROR 1048 (23000): Column 'id' cannot be null

1.3 UNIQUE:唯一约束

指定sn列是唯一的,不重复的

sql 复制代码
mysql> create table student
(id int not null,sn int unique,name varchar(20),qq_mail varchar(20));
Query OK, 0 rows affected (0.02 sec)
-- 我们可以在以下代码看到,sn只能插入一次相同的值,重复插入会报错
mysql> insert into student values(1,1,'qqq','qqq');
Query OK, 1 row affected (0.01 sec)
mysql> insert into student values(1,1,'qqq','qqq');
ERROR 1062 (23000): Duplicate entry '1' for key 'sn'
mysql> 

1.4 DEFAULT:默认值约束

指定插入数据时,name列为空,则默认值为unkown

sql 复制代码
create table student
(id int not null,sn int unique,name varchar(20) default 'unkown',qq_mail varchar(20));
-- 在下列代码可以看到name列没被插入,系统自动补成unkown
mysql> insert into student(id ,sn,qq_mail) values(2,2,'qqq');
Query OK, 1 row affected (0.01 sec)
mysql> select * from student;
+----+------+--------+---------+
| id | sn   | name   | qq_mail |
+----+------+--------+---------+
|  2 |    2 | unkown | qqq     |
+----+------+--------+---------+
1 row in set (0.00 sec)

1.5 PRIMARY KEY:主键约束(重点)

指定id列为主键

sql 复制代码
mysql> create table student
(id int not null primary key,name varchar(20));
Query OK, 0 rows affected (0.01 sec)

如何保证主键唯一呢?

MySQL提供一种"自增主键"这样的机制,主键经常使用int/big int,我们插入数据的时候,不必手动指定主键值,由数据库服务器自己分配一个主键,从1开始,依次递增的分配主键的值

对于整数类型的主键,常搭配子增长auto_increment来使用,插入数据对应字段不给值时(null,这里写作null其实是交给数据库服务器自行分配),使用最大值+1(相当于使用了一个变量来保存当前表的ID最大值,后续分配自增主键都是根据这个最大值分配的,如果手动指定的id也会更新最大值)

自动分配也有一定的局限性,如果是单个MySQL没问题,如果是一个分布式系统有多个MySQL服务器构成的集群,这个时候自增主键就不行了

sql 复制代码
-- 主键是NOT NULL和UNIQUE的结合,可以不用NOT NULL
create table student1
(id int  primary key auto_increment,name varchar(20));
Query OK, 0 rows affected (0.01 sec)
-- 插入多条数据,不指定id,我们来看一下效果
mysql> insert into student1(name) values('qqq');  
mysql> insert into student1(name) values('qqq');
mysql> insert into student1(name) values('qqq');
mysql> insert into student1(name) values('qqq');
mysql> select * from student1;
+----+------+
| id | name |
+----+------+
|  1 | qqq  |
|  2 | qqq  |
|  3 | qqq  |
|  4 | qqq  |
+----+------+
4 rows in set (0.00 sec)

-- 当我们指定了一个id,自增主键会更新最大值,我们来看下效果
mysql> insert into student1 values(11,'qqq');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student1(name) values('qqq');
Query OK, 1 row affected (0.00 sec)
mysql> select * from student1;
+----+------+
| id | name |
+----+------+
|  1 | qqq  |
|  2 | qqq  |
|  3 | qqq  |
|  4 | qqq  |
| 11 | qqq  |
| 12 | qqq  |
+----+------+
6 rows in set (0.00 sec)

分布式唯一id:=时间戳+主机编号/机房编号+随机因子

+指的是字符串拼接,不是算数相加

1.6 FOREIGN KEY:外键约束(重点)

外键用于关联其他表的主键或唯一键,描述了两个表之间的关联关系,只有用到的才受约束。

语法:

sql 复制代码
foreign key (子表的列) reference 主表(列);

进一步解释子表的列表示当前哪个表的哪个列被约束,主表(列)表示数据是被谁约束,也就是说,子表的列要出自于主表后括号中的那一列references表示当前这个表的这一列中的数据应该是出自另一个表的哪一列

  • 例:classes表中的数据约束了student表中的数据,classes称为父表(约束别人的表),student称为子表(被人约束的表)

创建班级表classes,id为主键:

sql 复制代码
mysql> create table classes
(id int primary key auto_increment,
name varchar(20),
`desc` varchar(100));

创建学生表student,一个学生对应一个班级,一个班级对应多个学生,使用id为主键,classes_id为外键,关联班级表id

sql 复制代码
mysql> create table student
(id int primary key auto_increment,
sn int unique,
name varchar(20) default 'unkown',
qq_mail varchar(20),
classes_id int,
foreign key (classes_id) references classes(id));
Query OK, 0 rows affected (0.02 sec)

-- 我们可以看到如下代码
mysql> insert into classes(name,`desc`) values('qqq','aaa');
Query OK, 1 row affected (0.00 sec)
mysql> select * from classes;
+----+------+------+
| id | name | desc |
+----+------+------+
|  1 | qqq  | aaa  |
+----+------+------+
1 row in set (0.00 sec)
-- 在这里我们发现把一个学生的班级设置为2会错误,因为classes表中没有id为2这个班级
mysql> insert into student(name,classes_id) values('qqq',2);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db_test`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`classes_id`) REFERENCES `classes` (`id`))
-- 班级设置为1则正确
mysql> insert into student(name,classes_id) values('qqq',1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from student;
+----+------+------+---------+------------+
| id | sn   | name | qq_mail | classes_id |
+----+------+------+---------+------------+
|  2 | NULL | qqq  | NULL    |          1 |
+----+------+------+---------+------------+
1 row in set (0.00 sec)

要对父表进行修改/删除操作,如果当前被修改/删除的值已经被子表引用了,这样的操作会失败,外键约束始终要保持子表中的数据要在对应的父表的列中存在,此时万一把父表这条数据删除了,就打破刚才的约束了,所以删除会报错

若想删除关联的表,只能先删除子表,再删父表

2.表的设计

根据实际的需求场景,明确当前要创建几个表,每个表啥样子,这些表之间是否存在一定联系

一般来说,每个实体都需要安排一个表,表的列就对应到实体的各个属性

  • 三大范式

2.1一对一

一个学生只能拥有***一个***账号

一个账号只能被***一个***学生拥有

2.2一对多

一个学生只能在***一个***班级中

一个班级可以包括***多个***学生

2.3多对多

一个学生可以选择***多门***课程

一门课程也可以包含***多个***学生

3.新增

把查询语句的查询结果作为插入的数值

语法:

sql 复制代码
insert into 表名 select * from 表名;
  • 例:设计一张用户表,把已有的学生数据复制进来
sql 复制代码
mysql> insert into test_user(name) select name from student1;
Query OK, 6 rows affected (0.01 sec)
Records: 6  Duplicates: 0  Warnings: 0
-- 我们可以看到,学生姓名已经被成功的复制进来
mysql> select * from test_user;
+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | qqq  | NULL |
|  2 | aaa  | NULL |
|  3 | bbb  | NULL |
|  4 | ccc  | NULL |
|  5 | ddd  | NULL |
|  6 | eee  | NULL |
+----+------+------+
6 rows in set (0.00 sec)

4.查询

4.1聚合查询

表达式查询 是针对列和列 之间进行运算的,
聚合查询 是相当于行和行之间进行运算的。

4.1.1聚合函数

SQL中提供了聚合函数,常见的统计总数,计算平均值等操作,可以使用聚合函数来实现,以下是常见的聚合函数:

函数 说明
COUNT(expr) 返回查询到的数据的数量,查询出来结果是集的行数
SUM(expr) 返回查询到的数据的总和,只能针对数字,把这一列的若干行求和,算术运算
AVG(expr) 返回查询到的数据的平均值
MAX(expr) 返回查询到的数据的最大值
MIN(expr) 返回查询到的数据的最小值
  • COUNT
sql 复制代码
-- 插入测试数据
mysql> insert into test_user (name) values('张三'),('李四'),('王五'),('赵六');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0
-- 查询(用*查询不可进行去重,NULL也算进去)
mysql> select count(*) from test_user;
+----------+
| count(*) |
+----------+
|        4 |
+----------+
1 row in set (0.00 sec)
mysql> select count(0) from test_user;
+----------+
| count(0) |
+----------+
|        4 |
+----------+
1 row in set (0.01 sec)
-- 再插入几组年龄数据,姓名为空
mysql> insert into test_user (age) values(10),(12),(13);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0
-- 我们先查询一下
mysql> select * from test_user;
+----+--------+------+
| id | name   | age  |
+----+--------+------+
|  8 | 张三   | NULL |
|  9 | 李四   | NULL |
| 10 | 王五   | NULL |
| 11 | 赵六   | NULL |
| 12 | NULL   |   10 |
| 13 | NULL   |   12 |
| 14 | NULL   |   13 |
+----+--------+------+
7 rows in set (0.00 sec)
-- 统计班级收集的年龄信息有多少个,年龄为NULL不会计入结果,也可进行去重
mysql> select count(age) from test_user;
+------------+
| count(age) |
+------------+
|          3 |
+------------+
1 row in set (0.00 sec)
  • SUM
sql 复制代码
mysql> select * from exam_result;
+------+-----------+---------+------+---------+
| id   | name      | chinese | math | english |
+------+-----------+---------+------+---------+
|    1 | 唐三藏    |    67.0 | 98.0 |    56.0 |
|    2 | 孙悟空    |    87.5 | 78.0 |    77.0 |
|    3 | 猪悟能    |    88.0 | 98.5 |    90.0 |
|    4 | 曹孟德    |    82.0 | 84.0 |    67.0 |
|    5 | 刘玄德    |    55.5 | 85.0 |    45.0 |
|    6 | 孙权      |    70.0 | 73.0 |    78.5 |
|    7 | 宋公明    |    75.0 | 65.0 |    30.0 |
+------+-----------+---------+------+---------+
7 rows in set (0.00 sec)

mysql> select sum(chinese) from exam_result;
+--------------+
| sum(chinese) |
+--------------+
|        525.0 |
+--------------+
1 row in set (0.00 sec)

sum函数中也可以使用表达式,先把对应列相加,得到的临时表再把这个临时表的结果进行相加,举例如下

sql 复制代码
mysql> select sum(chinese + math) from exam_result;
+---------------------+
| sum(chinese + math) |
+---------------------+
|              1106.5 |
+---------------------+
1 row in set (0.00 sec)
  • AVG
sql 复制代码
mysql> select avg(chinese+english+ math) as 平均总分 from exam_result;
+--------------+
| 平均总分     |
+--------------+
|    221.42857 |
+--------------+
1 row in set (0.00 sec)
  • MAX
sql 复制代码
mysql> select max(english) as 英语最高分 from exam_result;
+-----------------+
| 英语最高分      |
+-----------------+
|            90.0 |
+-----------------+
1 row in set (0.00 sec)
  • MIN
sql 复制代码
mysql> select min(math) as 数学最低分 from exam_result;
+-----------------+
| 数学最低分      |
+-----------------+
|            65.0 |
+-----------------+
1 row in set (0.00 sec)

4.1.2GROUP BY 子句

针对指定列进行分组,把这一列中值相同的行,分到一组中,然后得到若干个组,针对这些组分别使用聚合函数

语法

sql 复制代码
select column1,sum(column2)...... from table group by column1,column3;
  • 例:准备测试表和数据
sql 复制代码
mysql> insert into emp(name, role, salary) values
    -> ('马云','服务员', 1000.20),
    -> ('马化腾','游戏陪玩', 2000.99),
    -> ('孙悟空','游戏角色', 999.11),
    -> ('猪无能','游戏角色', 333.5),
    -> ('沙和尚','游戏角色', 700.33),
    -> ('隔壁老王','董事长', 12000.66);
Query OK, 6 rows affected (0.01 sec)
Records: 6  Duplicates: 0  Warnings: 0

+----+--------------+--------------+----------+
| id | name         | role         | salary   |
+----+--------------+--------------+----------+
|  1 | 马云         | 服务员       |  1000.20 |
|  2 | 马化腾       | 游戏陪玩     |  2000.99 |
|  3 | 孙悟空       | 游戏角色     |   999.11 |
|  4 | 猪无能       | 游戏角色     |   333.50 |
|  5 | 沙和尚       | 游戏角色     |   700.33 |
|  6 | 隔壁老王     | 董事长       | 12000.66 |
+----+--------------+--------------+----------+
6 rows in set (0.00 sec)

查询每个角色的最高工资、最低工资和平均工资

sql 复制代码
mysql> select role,max(salary),min(salary),avg(salary) from emp group by role;
+--------------+-------------+-------------+--------------+
| role         | max(salary) | min(salary) | avg(salary)  |
+--------------+-------------+-------------+--------------+
| 服务员       |     1000.20 |     1000.20 |  1000.200000 |
| 游戏角色     |      999.11 |      333.50 |   677.646667 |
| 游戏陪玩     |     2000.99 |     2000.99 |  2000.990000 |
| 董事长       |    12000.66 |    12000.66 | 12000.660000 |
+--------------+-------------+-------------+--------------+
4 rows in set (0.01 sec)

由于role这一列是group by指定的列,每一组的所有记录的role一定是相同的

如果分组之后不使用聚合函数,此时的结果就是查询出每一组中的某个代表数据,往往要搭配聚合函数使用,否则这里的查询结果就是没有意义的

  • 在group by中,可以一个SQL同时完成这两个类的筛选

注意:可搭配条件需要区分清楚,该条件是分组之前的条件还是分组之后的条件

分组之前:直接使用where即可,where子句一般写在group by前

分组之后:查询每个岗位的平均薪资,但是排除平均薪资超过2w的结果,须使用下列的HAVING描述条件

4.1.3HAVING

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

having语句一般写在group by 的后面

  • 显示平均工资低于1500的角色和他的平均工资
sql 复制代码
mysql> select role,max(salary),min(salary),avg(salary) from emp group by role having avg(salary)<1500;
+--------------+-------------+-------------+-------------+
| role         | max(salary) | min(salary) | avg(salary) |
+--------------+-------------+-------------+-------------+
| 服务员       |     1000.20 |     1000.20 | 1000.200000 |
| 游戏角色     |      999.11 |      333.50 |  677.646667 |
+--------------+-------------+-------------+-------------+
2 rows in set (0.00 sec)

4.2联合查询

(面试大概率考,但是实际开发中,而是要非常限制的使用,有时候使用起来很爽,但又不能广泛而不加节制的使用)

  • 关键思路:理解笛卡尔积的工作原理

笛卡尔积:通过排列组合的方式得到一张更大的表,笛卡尔积的行数(列数)是这两个表的行数相加(列数相加),如果仔细观察可以看到其中有些数据是非法的(不符合实际情况,无意义),进行多表查询时,需要把有意义的数据筛选出来,无意义的数据过滤掉

4.2.1内连接

语法:

sql 复制代码
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件
  • 例:查询许仙同学的成绩

步骤:

  1. 先把两个表进行笛卡尔积
sql 复制代码
mysql> select * from student,score ;
  1. 加上连接条件,筛选出有效数据
sql 复制代码
mysql> select * from student,score where student.id = score.student_id;
  1. 结合需求添加条件,针对结果进行筛选
sql 复制代码
mysql> select * from student,score where student.id = score.student_id and student.name = '许仙';
+----+------+--------+---------------+------------+----+-------+------------+-----------+
| id | sn   | name   | qq_mail       | classes_id | id | score | student_id | course_id |
+----+------+--------+---------------+------------+----+-------+------------+-----------+
|  4 |   31 | 许仙   | xuxian@qq.com |          1 | 10 |  67.0 |          4 |         1 |
|  4 |   31 | 许仙   | xuxian@qq.com |          1 | 11 |  23.0 |          4 |         3 |
|  4 |   31 | 许仙   | xuxian@qq.com |          1 | 12 |  56.0 |          4 |         5 |
|  4 |   31 | 许仙   | xuxian@qq.com |          1 | 13 |  72.0 |          4 |         6 |
+----+------+--------+---------------+------------+----+-------+------------+-----------+
4 rows in set (0.00 sec)
  1. 针对查询到的列进行精简
sql 复制代码
mysql> select student.name,score.score course from student,score where student.id = score.student_id and name = '许仙';
+--------+--------+
| name   | course |
+--------+--------+
| 许仙   |   67.0 |
| 许仙   |   23.0 |
| 许仙   |   56.0 |
| 许仙   |   72.0 |
+--------+--------+
4 rows in set (0.00 sec)
  • 例:查询所有同学的总成绩,及同学的个人信息
    此时同学的成绩是按照行来组织的,此处就是多行数据进行加和,聚合函数还需按同学进行分组
  1. 先进行笛卡尔积
sql 复制代码
mysql> select * from student,score where student.id = score.student_id;
  1. 指定连接条件
sql 复制代码
mysql> select * from student,score where student.id = score.student_id;
  1. 先精简列
sql 复制代码
mysql> select student.name,sum(score.score) from student,score where student.id = score.student_id;
  1. 针对上述结果进行group by聚合查询
sql 复制代码
mysql> select student.name,sum(score.score) from student,score where student.id = score.student_id group by name;
+-----------------+------------------+
| name            | sum(score.score) |
+-----------------+------------------+
| tellme          |            172.0 |
| 不想毕业        |            118.0 |
| 好好说话        |            178.0 |
| 白素贞          |            200.0 |
| 菩提老祖        |            119.5 |
| 许仙            |            218.0 |
| 黑旋风李逵      |            300.0 |
+-----------------+------------------+
7 rows in set (0.01 sec)
  • 例:查询所有同学的成绩以及个人信息
    列出每个同学,每门课程的的课程名字和分数
  1. 先进行笛卡尔积
sql 复制代码
mysql> select * from student,score,course;
  1. 指定连接条件筛选数据
sql 复制代码
mysql> select * from student,score,course where student.id = score.student_id  and course.id = score.course_id;
  1. 进行列的精简
sql 复制代码
mysql> select student.name,course.name,score.score from student,score,course where student.id = score.student_id and course.id = score.course_id;
+-----------------+--------------------+-------+
| name            | name               | score |
+-----------------+--------------------+-------+
| 黑旋风李逵      | Java               |  70.5 |
| 菩提老祖        | Java               |  60.0 |
| 白素贞          | Java               |  33.0 |
| 许仙            | Java               |  67.0 |
| 不想毕业        | Java               |  81.0 |
| 好好说话        | 中国传统文化       |  56.0 |
| tellme          | 中国传统文化       |  80.0 |
| 黑旋风李逵      | 计算机原理         |  98.5 |
| 白素贞          | 计算机原理         |  68.0 |
| 许仙            | 计算机原理         |  23.0 |
| 好好说话        | 语文               |  43.0 |
| 黑旋风李逵      | 高阶数学           |  33.0 |
| 菩提老祖        | 高阶数学           |  59.5 |
| 白素贞          | 高阶数学           |  99.0 |
| 许仙            | 高阶数学           |  56.0 |
| 不想毕业        | 高阶数学           |  37.0 |
| 黑旋风李逵      | 英文               |  98.0 |
| 许仙            | 英文               |  72.0 |
| 好好说话        | 英文               |  79.0 |
| tellme          | 英文               |  92.0 |
+-----------------+--------------------+-------+
20 rows in set (0.00 sec)

笛卡尔积的缺点:要提前考虑好表的数量,一旦表数量大或数目多,笛卡尔积大,如果对大表进行笛卡尔积,会产生大量临时结果,耗费时间 ,如果多表查询的数目非常多,SQL复杂,可读性差

4.2.2外连接

如果两个表里的记录都是存在对应关系,内外连接的结果一定是一致的,如果不存在对应关系,内外链接就会出现差别

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

左外连接就是以左侧的表为基准,保证左侧的表的每个数据都会在最终的结果里,如果在右侧表中不存在,对应的列就填成NULL

右外连接就是以右侧的表为基准,保证右侧的表的每个数据都会在最终的结果里,如果在右侧表中不存在,对应的列就填成NULL
语法:

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

-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件
  • 例:查询所有同学的成绩以及个人信息,如果同学没有成绩,也需要表示
sql 复制代码
 -- "老外学中文"同学没有考试成绩也显示出来了
 -- 左外连接
 mysql> select * from student stu left join score sco on stu.id = sco.student_id; 
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
| id | sn    | name            | qq_mail          | classes_id | id   | score | student_id | course_id |
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
|  1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com  |          1 |    1 |  70.5 |          1 |         1 |
|  1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com  |          1 |    2 |  98.5 |          1 |         3 |
|  1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com  |          1 |    3 |  33.0 |          1 |         5 |
|  1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com  |          1 |    4 |  98.0 |          1 |         6 |
|  2 |   835 | 菩提老祖        | NULL             |          1 |    5 |  60.0 |          2 |         1 |
|  2 |   835 | 菩提老祖        | NULL             |          1 |    6 |  59.5 |          2 |         5 |
|  3 |   391 | 白素贞          | NULL             |          1 |    7 |  33.0 |          3 |         1 |
|  3 |   391 | 白素贞          | NULL             |          1 |    8 |  68.0 |          3 |         3 |
|  3 |   391 | 白素贞          | NULL             |          1 |    9 |  99.0 |          3 |         5 |
|  4 |    31 | 许仙            | xuxian@qq.com    |          1 |   10 |  67.0 |          4 |         1 |
|  4 |    31 | 许仙            | xuxian@qq.com    |          1 |   11 |  23.0 |          4 |         3 |
|  4 |    31 | 许仙            | xuxian@qq.com    |          1 |   12 |  56.0 |          4 |         5 |
|  4 |    31 | 许仙            | xuxian@qq.com    |          1 |   13 |  72.0 |          4 |         6 |
|  5 |    54 | 不想毕业        | NULL             |          1 |   14 |  81.0 |          5 |         1 |
|  5 |    54 | 不想毕业        | NULL             |          1 |   15 |  37.0 |          5 |         5 |
|  6 | 51234 | 好好说话        | say@qq.com       |          2 |   16 |  56.0 |          6 |         2 |
|  6 | 51234 | 好好说话        | say@qq.com       |          2 |   17 |  43.0 |          6 |         4 |
|  6 | 51234 | 好好说话        | say@qq.com       |          2 |   18 |  79.0 |          6 |         6 |
|  7 | 83223 | tellme          | NULL             |          2 |   19 |  80.0 |          7 |         2 |
|  7 | 83223 | tellme          | NULL             |          2 |   20 |  92.0 |          7 |         6 |
|  8 |  9527 | 老外学中文      | foreigner@qq.com |          2 | NULL |  NULL |       NULL |      NULL |
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
21 rows in set (0.00 sec)

4.2.3自连接

自己和自己进行笛卡尔积,有时需要进行行和行的比较,而SQL只能进行行和列进行比较,此时就可以使用自连接,把行关系转成列关系

  • 例:查询成绩表中计算机原理成绩比Java成绩好的信息
sql 复制代码
mysql> select s1.student_id,s1.score,s2.score from score as s1,score as s2 where s1.student_id = s2.student_id and s1.course_id = 3 and s2.course_id = 1 and s1.score > s2.score;
+------------+-------+-------+
| student_id | score | score |
+------------+-------+-------+
|          1 |  98.5 |  70.5 |
|          3 |  68.0 |  33.0 |
+------------+-------+-------+
2 rows in set (0.01 sec)

4.2.4子查询

子查询的本质是套娃,把多个简单的SQL拼接成一个复杂的SQL,违背了一贯的变成原则

  • 例:查询与"不想毕业"的同班同学
sql 复制代码
mysql> select * from student where classes_id = (select classes_id from student where name = '不想毕业');
+----+------+-----------------+-----------------+------------+
| id | sn   | name            | qq_mail         | classes_id |
+----+------+-----------------+-----------------+------------+
|  1 | 9982 | 黑旋风李逵      | xuanfeng@qq.com |          1 |
|  2 |  835 | 菩提老祖        | NULL            |          1 |
|  3 |  391 | 白素贞          | NULL            |          1 |
|  4 |   31 | 许仙            | xuxian@qq.com   |          1 |
|  5 |   54 | 不想毕业        | NULL            |          1 |
+----+------+-----------------+-----------------+------------+
5 rows in set (0.00 sec)

4.2.5合并查询

把多个SQL的查询结果集合合并到一起

在实际应用中,为了合并多个select的执行结果,可以使用操作符union,union all。使用这两个时,前后查询的结果集中,字段需要一致
union:该操作符用于取得两个结果集的并集,当使用该操作符时,会自动去掉结果集中的重复行

  • 例:查询id小于3,或者名字为"英文"的课程
sql 复制代码
mysql> select * from course where id < 3 union select * from course where name = '英文';
+----+--------------------+
| id | name               |
+----+--------------------+
|  1 | Java               |
|  2 | 中国传统文化       |
|  6 | 英文               |
+----+--------------------+
3 rows in set (0.00 sec)

合并的两个SQL的结果集的列的个数和类型需要一致,union允许把两个不同的表查询结果合并到一起,并进行去重,若不想去重则使用union all

union all:不会去掉结果集中的重复行

  • 例:查询id小于3,或者名字为"Java"的课程
sql 复制代码
mysql> select * from course where id < 3 union all select * from course where name = '英文';
+----+--------------------+
| id | name               |
+----+--------------------+
|  1 | Java               |
|  2 | 中国传统文化       |
|  6 | 英文               |
+----+--------------------+
3 rows in set (0.00 sec)
相关推荐
NineData9 小时前
NineData 迁移评估功能正式上线
数据库·dba
tingshuo29179 小时前
S001 【模板】从前缀函数到KMP应用 字符串匹配 字符串周期
笔记
NineData14 小时前
数据库迁移总踩坑?用 NineData 迁移评估,提前识别所有兼容性风险
数据库·程序员·云计算
赵渝强老师17 小时前
【赵渝强老师】PostgreSQL中表的碎片
数据库·postgresql
全栈老石21 小时前
拆解低代码引擎核心:元数据驱动的"万能表"架构
数据库·低代码
倔强的石头_2 天前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
jiayou643 天前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
于眠牧北3 天前
MySQL的锁类型,表锁,行锁,MVCC中所使用的临键锁
mysql
李广坤4 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
Turnip12025 天前
深度解析:为什么简单的数据库"写操作"会在 MySQL 中卡住?
后端·mysql