【SQL武林秘籍】玩转表及其数据

news2024/12/23 18:40:03

目录

📖前言 

😀数据库约束类型

1️⃣not null 非空约束

2️⃣unique 唯一约束

3️⃣default 默认值约束

4️⃣primary key 主键约束

5️⃣foreign key 外键约束

6️⃣check 限制约束

😉新增(insert + select)

😄查询(进阶)

🔑聚合查询

🛴聚合函数

1️⃣count - 查询行数

2️⃣sum - 求和

3️⃣avg - 求平均值

4️⃣max - 求最大值  / min - 求最小值

🛵分组聚合查询 (group by 操作)

🔑联合查询

1️⃣内连接

2️⃣外连接

3️⃣自连接

4️⃣子查询

5️⃣合并查询

🎉小结ending


📖前言 

书接上回, 在认真学习本人的SQL入门文章后, 想必各位同学对SQL的操作已经基本拿捏了, 进来我们来学习一下SQL的进阶操作.

而本文的主要内容是, 在有一定SQL语言基础下, 学习数据库的约束类型(以MySQL数据库为例), 数据库中表及其数据的进阶操作.

本文篇幅较长, 关注收藏, 耐心食用吧🧐

🚄此为SQL系列第二篇, 如果还未学习基础SQL语言的同学, 可以移步系列第一篇文章, 即可快速上手↓

【SQL武林秘籍】零基础带你快速上手SQL语言http://t.csdn.cn/dX6Nd

😀数据库约束类型

简单来说, 约束其实就是数据库针对里面的数据能写什么, 给出的一组检验规则.

当我们在学习desc描述表结构操作时, 有没有同学对里面的结构产生疑问?

 表结构中, Field代表字段名, Type代表其字段类型, 那后面的Null, Key, Default, Extra是代表什么意思呢? 这就需要讲到我们数据库的约束, 接下来给大家解答这些疑问. 

先给大家看一下, 在创建表时, 该如何指定他的约束类型

注意: 当我们不指定约束类型时, Null默认为YES, Default默认为Null.

常见的约束有以下几种:

约束类型
说明
示例
null使用not null指定列不为空name varchar(20) not null,
unique指定列为唯一的, 不重复的name varchar(20) unique,
default指定列为空时的默认值age int default 20,
primary keynot null 和 unique 的结合id int primary key,
foreign key关联其他表的主键或唯一键foreign key .. references ..
check保证列中的值符合指定的条件check(sex='男' or sex='女')

语法:

create table 表名(字段名 字段类型 约束类型, ...);

1️⃣not null 非空约束

not null是用来指定某列不能存储null值, 表示该字段始终包含一个不为空的值, 如果插入数据时, 不指定一个确定值或指定值为空, 那么就会插入失败, 也无法使用update将确定值更新为null

下面我们来创建一个图书表, 将图书id设置为not null约束.

drop table if exists book;

create table book(id int not null, name varchar(20));

 如图, 创建成功, 我们设置了两个字段, 一个是图书id, 一个是图书名称, 并将图书id用not null约束, 我们看一下约束后的表结构与普通表有什么区别.

可以看到字段id的Null属性, 是NO, 与默认的YES不同, 现在我们试着在表里插入一个id为空值的图书.

insert into book (id) value (null);

 插入失败, 报错了, 意思是id列的值不能为null(空值)

2️⃣unique 唯一约束

unique约束是用来保证某列的每行必须有唯一值, 不能有重复的数据, 如果插入值时, 表中已经存在一个相同值时, 会导致插入失败, 更新也是一个道理.

我们还是来拿book表举例.

drop table if exists book;

create table book(id int unique, name varchar(20));

 创建成功, 我们再查看一下book表结构是什么样子的.

可以看到字段id的Key属性是UNI(unique), 意味着这个字段存储的数据不可以重复, 我们现在试着插两个相同id的图书.

insert into book values (1, '图书一'), (1, '图书二');

 

插入失败,  报错了, 意思是重复的给id列插入1

3️⃣default 默认值约束

default用来规定, 还没被赋值的列的初始值, 我们还是举一个例子来说明.

给book插入数据时, name列为空, 默认值设置为unknow.

drop table if exists book;

create table book(id int, name varchar(20) default 'unknow');

创建成功, 我们再查看一下book表结构是什么样子的.

可以看到字段name的Default属性写着unknow, 不赋值时字段的默认值是unknow.

现在我们插入一条空名图书.

 可以看到, 即使我们没有给name赋值, 也有一个默认值unknown.

4️⃣primary key 主键约束

我们可以将 primary key 理解为 not null 和 unique 的结合, 确定某列有唯一标识, 不能为空, 也不能有重复数据. 主键 = unique + not null

drop table book;

create table book(id int primary key, name varchar(20));

 

创建成功, 我们来看一下表结构是什么样子.

可以看到字段id的Key属性是PRI(primary key), 意味着这个字段存储的数据不可以为空, 也不可以重复, 我们就不插入数据来验证了, 与之前unique + not null的效果一致, 我们讲一下primary key的特殊用法.

自增主键(primary key auto_increment)

对于整数类型的主键, 我们可以搭配自动增长auto_increment来使用, 插入数据对应字段不给值时, 给默认赋值最大值 + 1

我们来创建一张有自增主键的book表

drop table book;

create table book(id int primary key auto_increment, name varchar(20));

我们再看一下表结构

可以看到, 相较于普通主键, 自增主键的Extra额外属性中, 写着auto_increment, 代表着这个字段是可以自动增长的.

在使用时, 我们只需要在insert语句中, 不给id赋值即可.

现在我们再插入三个图书数据进去, 看一下是什么样的效果.

insert into book (name) values ('图书一'), ('图书二'), ('图书三');

可以看到, 即使我们没有设置字段id的值, 带有自增主键的字段id, 可以自动生成值, 并且是递增的.

如果我们手动加入一个id进去, 自增就会自动缩印以上所有数据中的最大值, 并且+1赋给新的id.

5️⃣foreign key 外键约束

外键通常用来在两个表之间建立关系, 外键的主要用途是维持实体的两个独立实例之间的数据完整性, 下面我来用一张 class 表与一张 student 表来带大家简单了解一下外键的使用. 在设定时, 我们让 student 受到 class 的约束, 那么 class 就叫做 student 的父表(parent), student 就是 class 的子表(child).

# 创建class表
create table class(classId int primary key auto_increment, className varchar(20));

# 创建student表, 将classId与class表中classId关联
# 语法结构 foreign key (子表列名) references 父表名(父表列名);
create table student(studentId int primary key auto_increment, name varchar(20), classId int,foreign key (classId) references class(classId));

 我们再来看一下两个表的结构

 那么外键具体是帮助我们怎么约束呢? 接下来我们进行一个 insert 插入操作, 在 student 表中添加姓名为张三, 班级为1班的同学, 你们猜会发生什么呢?

可以看到, 这里出现错误了, 我们可以简单看一下报错信息, Cannot add or update a child row, 意思是不能添加或修改子表的行, a foreign key constraint fails, 意思是外键约束失败.

那么为什么会发生这样的错误呢? 原因是我们对 student 表中的 classId 进行了外键约束, 只有父表内的 classId 有其插入对应的数据时, 才可以正确进行插入. 

接下来, 我们在 class 表中插入一个班级信息.

我们再尝试一遍上面对 student 的插入张三的操作.

 可以看到, 这次插入成功了, 可能有细心的同学会注意到, 明明是第一次成功插入数据, 为什么主键Id的值为2, 那是前面尝试添加过一次数据, 但是失败了, 不过自增主键还是增加了.

约束是父表与子表双方的

在进行外键约束操作时, 我们要注意约束其实是相对的, 父表在约束子表的同时, 其实子表凡响的约束了父表, 大家可以想一想, 当有子表依赖父表时, 我们可以直接将父表中的数据删除吗?

 可以看到, 删除操作失败了, Cannot delete or updata a parent row, 不能删除或修改父表数据.

所以当子表对父表有依赖时, 父表内被依赖的数据是无法直接删除的, 只有子表中依赖其的数据被删除后, 才可以删除父表中被依赖数据, 这就是子表对父表的约束.

6️⃣check 限制约束

check限制约束是 MySQL 8.0 之后新增的约束类型, 在之前的版本内使用该约束会被忽略, 但也不会报错. 大家简单认识一下即可.

下面给大家一个check约束使用的案例, 此案例表示列 sex 的值只能为 男 或者 女.

create table test_user (
   id int,
   name varchar(20),
   sex varchar(1),
   check (sex ='男' or sex='女')
);

 

 可以看到, 当我们在尝试插入一个名为张三, 性别为 '?' 的人时, 检测到插入数据是违法的, 所以无法插入.

😉新增(insert + select)

这里我要讲的进阶内容的新增, 就是将新增和查询联合起来, 其实就是 insert + select, 可以实现将查询到的结果作为新增的数据插入到表中.

接下来我们建立两个 student 学生表 student1 和 student2 , 并且在 student1 中插入三条数据.

 接下来, 我们进行一个新增操作, 目的是将查询到 student1 表中的所有数据添加到 student2 表中.

insert into student2 select * from student1;

 可以由结果看到新增数据成功了, 即向 student2 中插入了 student1 中的全部数据.

注意: 在进行这种方式的插入时, 查询的表的结果, 得到的列数, 类型需要和插入的表的列数, 类型相匹配.

😄查询(进阶)

🔑聚合查询

聚合查询, 就是在查询过程中, 将表的行和行之间进行一定的运算, 聚合查询依赖于聚合函数, 这些函数是 SQL 中提供的库函数.

🛴聚合函数

常见的聚合函数有以下几种:

函数说明
count
返回查询到的数据的 数量
sum
返回查询到的数据的 总和,不是数字没有意义
avg
返回查询到的数据的 平均值,不是数字没有意义
max
返回查询到的数据的 最大值,不是数字没有意义
min
返回查询到的数据的 最小值,不是数字没有意义

1️⃣count - 查询行数

例: 查询 student1 表中所有行的数量

select count(*) from student1;

 

例: 查询 student1 表中 id 列数据的数量

select count(id) from student1;

例: 当表中有 null 数据时, 查询 name 列数据的数量

在进行查询操作前, 我们先给 student1 添加一个 id 为 4 , name 为 null 的数据.

然后按照 id 和 name 来分别进行 count 的聚合查询

# 插入数据
insert into student1 values(4, null);
# 按id进行count聚合查找
select count(id) from student1;
# 按name进行count聚合查找
select count(name) from student1;

 可以看到, 如果查询的单列中, 有 null 数据时, 会将其省略.

2️⃣sum - 求和

sum求和的聚合查找, 只是针对数字列有效, 如果是字符串列, 则无法进行计算.

例: 查询 student1 中 id 列的值的和

select sum(id) from student1;

  

例: 查询 student1 中 name 列的值的和 (字符串列)

select sum(name) from student1;

 我们可以看到, 当计算字符串列时, 结果会出现 0 , 并且会提示 warnings 信息, 在这里我们可以使用 show warnings; 来进行查看.

 可以看到, 报错信息显示, 将张三, 李四, 王五字符串类型给截断了.

注: 当查询数据中有null值时, 会自动跳过当前行, 不进行计算

3️⃣avg - 求平均值

例: 查询 student1 中 id 列的值的平均值

select avg(id) from student1;

avg求平均值的操作就不具体展开讲了, 其实是与上面sum操作注意点是一致的. 

4️⃣max - 求最大值  / min - 求最小值

由于 max 与 min 是相反的, 其逻辑也比较简单, 我就把他放在一个小点里来说.

例: 查询 student1 中 id 列的最大值和最小值

select max(id),min(id) from student1;

 

🛵分组聚合查询 (group by 操作)

select 中使用 group by 子句可以对指定列进行分组查询, 需要满足: 使用 group by 进行分组查询时, select 指定的字段必须是“分组依据字段”, 其他字段若想出现在 select 中则必须包含在聚合函数中.

select column1, sum(column2), .. from table group by column1,column3;

让我们来准备一个测试表以及插入一些测试数据: 职员表, 有 id , name , role , salary.

create table emp(
 id int primary key auto_increment,
 name varchar(20) not null,
 role varchar(20) not null,
 salary numeric(11,2)
);

insert into emp(name, role, salary) values
('马云','服务员', 1000.20),
('马化腾','游戏陪玩', 2000.99),
('孙悟空','游戏角色', 999.11),
('猪无能','游戏角色', 333.5),
('沙和尚','游戏角色', 700.33),
('隔壁老王','董事长', 12000.66);

例: 查询每个角色的最高工资、最低工资和平均工资 (group by role)

select role,max(salary),min(salary),avg(salary)from emp group by role;

以上便求出了每个角色的平均薪资

- 利用having和where来进行条件筛选

1. group by 分组前可使用 where 条件来进行筛选, 我们可以试着求一下每个角色的平均薪资, 但是需要刨除掉孙悟空.

select role,avg(salary) from emp where name != '孙悟空' group by role;

 2. group by 分组后可使用 having 条件来进行筛选, 试着求每个岗位的平均薪资, 但是要刨除掉董事长.

select role,avg(salary) from emp group by role having role != '董事长';

 3. 我们也可以同时使用 where 和 having 在分组前和分组后来进行筛选

select role,avg(salary) from emp where name != '孙悟空' group by role having role != '董事长';

🔑联合查询

实际开发中, 很多数据往往来自于不同的表, 而联合查询就是把多个表联合到一起进行查询, 多表查询是对多张表的数据取笛卡尔积:

笛卡尔积得到的表的列数, 为两个表的列数之和, 行数为之积, 但由于笛卡尔积是排列组合后的结果, 这里面的有些数据是无效的.

让我们来创建一些测试表及其数据:

drop table if exists classes;
drop table if exists student;
drop table if exists course;
drop table if exists score;

create table classes(id int primary key auto_increment,name varchar(20), `desc`varchar(100));

create table student(id int primary key auto_increment,sn varchar(20),name varchar(20),qq_mail varchar(20),classes_id int);

create table course(id int primary key auto_increment,name varchar(20));

create table score(score decimal(3,1),student_id int,course_id int);

insert into classes(name, `desc`) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');
insert into student(sn, name, qq_mail, classes_id) values
('09982','黑旋风李逵','xuanfeng@qq.com',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','xuxian@qq.com',1),
('00054','不想毕业',null,1),
('51234','好好说话','say@qq.com',2),
('83223','tellme',null,2),
('09527','老外学中文','foreigner@qq.com',2);
insert into course(name) values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');
insert into score(score, student_id, course_id) values
-- 黑旋风李逵
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
-- 菩提老祖
(60, 2, 1),(59.5, 2, 5),
-- 白素贞
(33, 3, 1),(68, 3, 3),(99, 3, 5),
-- 许仙
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
-- 不想毕业
(81, 5, 1),(37, 5, 5),
-- 好好说话
(56, 6, 2),(43, 6, 4),(79, 6, 6),
-- tellme
(80, 7, 2),(92, 7, 6);

共创建四张表:

看一下classes表中数据:

看一下course表中数据:

看一下score表中数据:

看一下student表中数据:

联合查询中, 主要有以下几种方式, 让我来给大家一一讲解. 

1️⃣内连接

例1: 查询"许仙"同学的成绩

想要查找学生以及其成绩, 我们需要用到两个表, sutdent 和 score, 这种情况, 我们就需要进行联合查询

# 两种连接方式
# 1. 使用 ',' 来连接两表
select * from student, score;

# 2. 使用 "join ... on ..." 来连接两表
#    外连接时必须使用 "join on" , 外连接我们在之后讲解.
select * from student join score;

由于查询结果有160行数据, 我们给大家截取一部分来看, 160行数据就是两个表的行数相乘得到的积, 20 * 8 = 160.

我们可以看到, 如果我们不额外进行操作的话, 笛卡尔积得到的联合表, 是有很多无效数据的, 我们需要加一些修饰来筛选出有效数据, 在这个例子中, 我们需要筛选出一个学生的课程成绩, 要求两表中的学生ID是相同的, 我们可以使用 " 表名.列名 " 的形式来进行选择, student.id = score.student_id.

# 两种连接方式
# 1. 使用 "where" 搭配 ',' 来筛选有效信息
select * from student, score where student.id = score.student_id;

# 2. 使用 "join ... on ..." 来筛选有效信息
select * from student join score on student.id = score.student_id;

 可以看到经过筛选后, 160行数据只剩下了20行, 并且都是有效数据, 接下来我们就可以利用学过的基础查询语句来实现查询"许仙"同学的成绩.

在这里我们就使用 "join on" 来进行查询. 

 这样我们便查询到了许仙同学的成绩.

例2: 查询"许仙"同学的成绩并要求显示课程名称

我们再思考一下这个问题, 如果要求要显示其课程的名称该怎么办呢? 这就需要查询三个表, student, score, course, 才可以实现该操作, 那么我们该如果连接三个表呢? 在有了之前一个案例的经验后, 我们话不多说, 直接上代码来看. 

select 
    student.name,
    score.score,
    course.name as course_name # 给course.name取别名
from 
    student,
    score,
    course 
where 
    student.id = score.student_id 
    and 
    score.course_id = course.id 
    and 
    student.name = '许仙';

由于本条语句有点复杂, 我将代码分开给大家看

可以看到, 当我们连接三张表时, 需要有两个连接条件:

  1. student.id = score.student_id 用来筛选student表和score表学生id相同的数据
  2. score,course_id = course.id 用来筛选score表和course表课程id相同的数据

例3: 查询每个同学的总成绩, 及其个人信息.

在本案例中, 我们需要查找每个学生的总成绩, 说到总成绩, 大家熟悉吗? 有没有想到我们之前讲到的聚合查询, 聚合查询中有一个聚合函数是 sum 求和函数, 我们可以利用 sum 再搭配联合查询 student 表和 score 表来实现本操作. 当然要使用 sum 求和函数, 我们还需要利用 "group by" 按照 student.name 来进行分组.

select 
    student.name,
    sum(score.score) 
from 
    student,score 
where 
    student.id = score.student_id 
    group by 
    student.name;

总结一下:

 在完成三个案例后, 你肯定对联合查询有了一个基本的了解, 我们在这里总结一下联合查询的实现步骤: 看, 求, 筛, 简

  • 看: 分析清楚实际需求中, 涉及到的信息都在哪些表中.
  • 求: 针对多个表求其笛卡尔积.
  • 筛: 筛选出其中的有效数据, 找到关联条件 
  • 简: 结合需求中的条件, 进一步完善查询, 并可以针对列进行精简.

2️⃣外连接

上面讲到的联合查询, 其实就是最基本的, 也是最常用的内连接, 此外我们还有一些连接方式, 我们先讲一下外连接.

外连接和内连接在本质上都是进行笛卡尔积, 但是在细节中还是有所差别的. 

而外连接又分为左外连接和右外连接两种情况. 

由于我们之后要进行外连接, 所以我们采用 "join on" 内连接方法来查询一下数据.

例: 查询所有同学的成绩, 及其个人信息.

select * from student join score on student.id = score.student_id

 

这是我们内连接查询到的结果. 接下来我们尝试进行一下外连接, 来看一下外链接的作用是什么.

例: 查询所有同学的成绩, 及其个人信息, 如果该同学没有考试成绩, 也需要显示

左外连接

select * from student left join score on student.id = score.student_id;

可以看到 "老外学中文" 并没有考试成绩, 但是也显示出来了, 这就是外连接的作用, 当我们进行左外连接时, 就是以左侧的表为准, 左侧表其中的数据均能体现出来, 即使是与其对应的右侧表中的值为空值, 甚至数据无法对应时, 也能体现左侧表中的所有数据. 右外连接与其相反.

此操作对应的右外连接为

select * from score right join student on student.id = score.student_id;

 

总结一下: 相较于内连接来说, 外连接的使用是比较少的, 一般只用于一些特定场景, 同学认识该操作即可, 等真需要使用时, 回来再看一下, 回想起来基本的操作就OK了 

3️⃣自连接

自连接大家听名字应该就知道它是如何进行连接的, 没错, 就是自己和自己连接, 自己和自己做笛卡尔积, 自连接就是指在同一张表连接自身进行查询这是特殊情况下的特殊操作, 并非是一般用法, 这个操作本质上是将 "行" 转换成 "列"

例1: 显示所有“计算机原理”成绩比“Java”成绩高的成绩信息

在本案例中, 我们需要找到哪些同学的 "计算机原理" 比 "Java" 高, 如果我们直接查询 score 成绩表 

可以看到:

 当前的课程, 与其分数是行关系, 这样我们不方便查找, 这时我们就需要将行转换为列, 需要用到自连接. 在使用自连接时, 我们需要注意一个问题, 在连接时, 两个表必须指定一个别名, 否则两个都是 score 表, 会出现语法错误.

给大家看一下自连接的实现步骤:

# 先查询“计算机原理”和“Java”课程的id
select id,name from course where name='Java' or name='计算机原理';

# 再查询成绩表中,“计算机原理”成绩比“Java”成绩 好的信息
select
    s1.* 
from
    score s1, # 给score取别名为s1
    score s2  # 给score取别名为s2
where
    s1.student_id = s2.student_id
    and
    s1.score < s2.score
    and 
    s1.course_id = 1
    and 
    s2.course_id = 3;

# 也可以使用join on 语句来进行自连接查询
select
    s1.* 
from
    score s1 # 给score取别名为s1
    join 
    score s2 # 给score取别名为s2
    on 
    s1.student_id = s2.student_id
    and s1.score < s2.score
    and s1.course_id = 1
    and s2.course_id = 3;

 

 经过自连接筛选之后, 得到了我们想要的结果.

思考一下: 其实以上查询, 只显示了成绩信息, 并且是分布执行的,  如果要显示学生及成绩信息,并在一条语句显示, 该怎么做呢?

这就需要将自连接, 与我们之前学的内连接相结合起来了.

select
    stu.*,
    s1.score Java,
    s2.score 计算机原理
from
    score s1
    join score s2 on s1.student_id = s2.student_id
    join student stu on s1.student_id = stu.id
    join course c1 on s1.course_id = c1.id
    join course c2 on s2.course_id = c2.id
    and s1.score < s2.score
    and c1.name = 'Java'
    and c2.name = '计算机原理';

 

总结一下: 学到这里, 大家应该可以发现, SQL的逻辑表达能力是有限的, 很多时候业务的逻辑是很难实现的, 不是做不了, 而是代价太大, 即使是实现了一些比较复杂的逻辑, 也需要很复杂的语句来完成, 代码可读性是很差的, 相比之下, 使用Java这样的语言来实现复杂逻辑是更加合适的.

4️⃣子查询

子查询是指嵌入在其他 SQL 语句中的 select 语句, 也叫作嵌套查询, 大家可以把他想象为 "套娃", 一层套一层, 把多个查询语句合并成一个.

而子查询也分为两种查询方法: 单行子查询多行子查询

1. 单行子查询

例1: 查询与"不想毕业"同学的同班同学

我们不使用子查询的话, 用之前学的查询知识, 应该如何去做呢? 是不是应该把这个操作分为两步, 先查询 "不想毕业" 同学是在哪个班, 然后再查询, 和查询到的班级号相同的同学.

# 1. 查询'不想毕业'同学的班级号
select classes_id from student where name = '不想毕业';

# 2. 第一步查询结果为1, 查询1班的所有同学
select * from student where classes_id = 1;

 我们可以将两步操作嵌套起来, 变为一步操作, 这就是子查询.

select * from student where classes_id = (select classes_id from student where name = '不想毕业');

 

 可以看到, 与分步查询的结果是一样的.

2. 多行子查询

在上述查询中, 我们嵌套的查询结果只有一条记录, 如果我们需要嵌套一个返回多行记录的查询结果, 该怎么办去做?

例2: 查询"语文"或"英文"课程的成绩信息

我们还是先进行基本的分步操作, 先查询到两个课程的id, 再拿着课程id去分数表中查找.

# 1. 查询两个课程的id
select id from course where name = '语文' or name = '英文';

# 2. 拿着课程id去分数表中查找, 还记着 "in" 运算符吗?
select * from score where course_id in (4, 6);

 那么如何将两步操作嵌套起来呢? 我们只需要将 in 运算符中的(4, 6), 替换为多行查询结果即可.

注意一下: 子查询在实际开发当中使用的时候一定要谨慎, 一旦其中嵌套的层次多了, 那么对于代码的可读性将会是毁灭性的打击.

5️⃣合并查询

在实际应用中, 为了合并多个select的执行结果, 可以使用集合操作符 union, union all.

使用 union 和 union all 时, 前后查询的结果集中, 字段需要保持一致.

1. union

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

例1: 查询id小于3, 或者名字为"英文"的课程

# 使用 union 来进行合并查询
select * from course where id < 3
union
select * from course where name = '英文';

 我们使用之前学过的运算符 or 来实现也可以, 但是要注意 or 只能针对一个表中的数据, 而 union 能针对多个表.

查询得到的结果与 union 是一样的

2. union all

 该操作符用于取得两个结果集的并集. 但是与 union 有些不同, 当使用 union all 时, 不会自动去掉结果集中的重复行.

例2: 查询id小于3, 或者名字为"Java"的课程

select * from course where id < 3
union all
select * from course where name = 'Java';

 可以看到结果集中出现重复数据Java, 如果我们使用 union 来操作, 就可以避免了

union运算符则没有出现重复数据Java. 


🎉小结ending

✨感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.

✨数据库SQL语言的知识就先告一段落了, 学习完初阶进阶(本篇)两篇文章后, 你一定可以实现轻松操作表数据, 之后我还会有章节给大家讲一下数据库中表的简单设计, 请关注插眼, 带你继续学习数据库的知识.

再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!

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

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

相关文章

Podman 是 Docker 的直接替代品吗?

在许多地方&#xff0c;你可以读到Podman是Docker的替代品。但是&#xff0c;真的像听起来那么简单吗&#xff1f;在这篇文章中&#xff0c;你将从一个可以立即投入生产使用的Dockerfile开始&#xff0c;并执行Podman命令&#xff0c;就像你使用Docker时会做的那样。让我们看看…

【Vite环境变量】import.meta.env 和 loadEnv使用和区别

前言 我们在做项目时需要各种配置信息&#xff08;如应用标题、API 地址等&#xff09;&#xff0c;这些配置信息可能在不同环境下有所不同&#xff08;如开发环境和生产环境&#xff09;。 如果每次更改开发或者更改生产环境需要修改源代码中的相关配置&#xff0c;这会导致…

老生常谈:接口幂等性,防止并发插入重复数据

分布式系统中&#xff0c;接口幂等性问题&#xff0c;对于开发人员来说&#xff0c;是一个跟语言无关的公共问题。不知道你有没有遇到过这些场景&#xff1a; 有时我们在填写某些form表单时&#xff0c;保存按钮不小心快速点了两次&#xff0c;表中竟然产生了两条重复的数据&a…

AI时代的三类人:探索掌握AIGC,引领未来的人才之路

&#xff08;本文阅读时间&#xff1a;6 分钟&#xff09; 1 AI时代&#xff1a;ChatGPT引领AIGC技术革命 对于那些热衷于探索新技术的小伙伴而言&#xff0c;ChatGPT早已超越了抽象的概念&#xff0c;我们对其能力已有所了解。那么&#xff0c;ChatGPT究竟能够做些什么呢&…

Java 集合全教程

一、集合简介 集合&#xff08;有时称为容器&#xff09;只是将多个元素分组到单个单元中的对象。集合用于存储、检索、操作和传达聚合数据。通常&#xff0c;它们表示形成自然组的数据项&#xff0c;例如扑克手&#xff08;纸牌集合&#xff09;、邮件文件夹&#xff08;字母…

【Java多线程进阶】synchronized工作原理

前言 本期讲解 synchronized 工作的原理以及常见的锁优化机制&#xff0c;相信大家在看完这篇博文后对 synchronized 工作流程有一定的理解。话不多说&#xff0c;让我们快速进入学习吧~ 目录 1. 锁的工作流程 2. 偏向锁 3. 轻量级锁和重量级锁 3.1 轻量级锁 3.2 重量级锁…

Kubernetes基本存储

Kubernetes基本存储 容器的生命周期可能很短&#xff0c;会被频繁地创建和销毁&#xff0c;容器销毁时&#xff0c;保存在容器中的数据也会被清除。为了持久化保存容器中数据&#xff0c;引入Volume概念。 Volume时Pod中多个容器共同访问的共享目录&#xff0c;它被定义在Pod中…

“碳”寻青蓝锦色,锦江酒店(中国区)用行动点亮酒店可持续发展

第52个世界环境日之际&#xff0c;为响应“减塑捡塑”号召&#xff0c;锦江酒店&#xff08;中国区&#xff09;以“‘碳’寻青蓝锦色”为主题&#xff0c;在6月5日至6月11日期间&#xff0c;开启第二届“绿色生活创益周”&#xff0c;通过线上线下联动&#xff0c;倡导时尚低碳…

2023智源大会议程公开丨类脑计算论坛

6月9日&#xff0c;2023北京智源大会&#xff0c;将邀请这一领域的探索者、实践者、以及关心智能科学的每个人&#xff0c;共同拉开未来舞台的帷幕&#xff0c;你准备好了吗&#xff1f;与会知名嘉宾包括&#xff0c;图灵奖得主Yann LeCun、图灵奖得主Geoffrey Hinton、OpenAI创…

Mocha AE:Clip 模块

Clip&#xff08;剪辑&#xff09;模块主要用于对素材或遮罩文件的格式进行查看或设置&#xff0c;包括视频格式、时间码格式、色彩空间等&#xff0c;还可以进行裁剪。 General 常规 Input 输入 当前图层素材。 Matte for Layer n 图层 n 的遮罩 Name 名称 显示素材的名称。 …

通信大史记:互联网的起源故事

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 卷圈 运营 / SandLiu 卷圈 监制 / 姝琦 文案 / 朱峰 产品统筹 / bobo 这是一期“两年更”的节目&#xff0c;通信大史记录完第一期后&#xff0c;因为资料准备和主播时间的关系一直没有后续更新。今天&#xff0c;我们…

nodejs的path模块

path路径模块 path模块是Node.js官方提供的&#xff0c;用来处理路径的模块。提供一系列的方法和属性&#xff0c;用来满足用户对路径的处理需求。 例如&#xff1a; 如果在js代码中&#xff0c;使用path模块来处理路径&#xff0c;需要先导入 const pathrequire(path)常用的…

chatgpt赋能python:Python如何调成白色的SEO文章

Python 如何调成白色的 SEO 文章 介绍 Python 是一种流行的编程语言&#xff0c;在数据分析、人工智能、Web 开发以及其他许多领域都有广泛的应用。然而&#xff0c;很少有人会把 Python 与 SEO 联系起来。 事实上&#xff0c;Python 是一个强大的工具&#xff0c;可以帮助 …

软件工程师,学会封装不香么

什么是封装 从面向对象编程的角度来说&#xff0c;封装是指利用抽象数据类型将数据和基于数据的操作封装在一起&#xff0c;使其构成一个不可分割的独立实体&#xff0c;数据被保护在抽象数据类型的内部&#xff0c;尽可能地隐藏内部的细节&#xff0c;只保留一些对外接口使之与…

rk3568 TF卡启动

rk3568 SD卡启动 SD卡启动系统&#xff0c;它可以让rk3568在没有硬盘或其他存储设备的情况下启动和运行操作系统。这使得rk3568变得与树梅派一样灵活切换系统&#xff0c;与此同时进行故障排查和修复&#xff0c;而不需要拆卸设备或者使用专业的烧录工具。SD卡启动还可以方便地…

音视频同步的方法:深入探索基于FFmpeg的音视频同步策略

音视频同步艺术&#xff1a;深入探索基于FFmpeg的同步策略 &#xff08;一&#xff09;音视频同步的基本概念与重要性&#xff08;Basic Concepts and Importance of Audio-Video Synchronization&#xff09;1.1 音视频同步的定义与影响&#xff08;Definition and Impact of …

【SQL】Oracle数据库实现远程访问

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle&#xff0c;是甲骨文公司的一款关系…

【Python入门】Python循环语句(for循环的基础语法)

前言 Python循环语句 1. for循环的基础语法1.1 for循环1.2 程序中的for循环1.3 for循环语句1.4 for循环注意点1.5 总结1.6 练习案例&#xff1a;数一数有几个a 2. range语句2.1 range语句讲解2.2 for循环遍历range序列2.3 总结2.4 练习案例&#xff1a;有几个偶数 3. 变量作用域…

RFID软件:简介、功能和应用范围

在当今快节奏的商业环境中&#xff0c;RFID&#xff08;射频识别&#xff09;技术已经成为物流、供应链和库存管理等领域中不可或缺的工具。本文将向您介绍RFID软件的基本知识&#xff0c;探讨其功能和广泛应用的范围。 第一部分&#xff1a;RFID软件简介 RFID软件是一种应用…

【开源项目】SofaBoot实现Spring Bean 异步初始化的源码拆解

使用场景 在实际使用 Spring/Spring Boot 开发中&#xff0c;一些 Bean 在初始化过程中执行准备操作&#xff0c;如拉取远程配置、初始化数据源等等。在应用启动期间&#xff0c;这些 Bean 会增加 Spring 上下文刷新时间&#xff0c;导致应用启动耗时变长。 Demo展示 Spring…