MySQL入门篇(SQL语句、函数、约束、多表查询、事务)

MySQL概述

数据库:存储数据的仓库,数据是有组织的进行存储。(DB,DataBase)
数据库管理系统:操作和管理数据库的大型软件(DataBase Management System,DBMS)
数据库系统:包含数据库、数据库管理系统和数据库管理和操作人员(DataBase System,DBS)
简记为:DBS=DBMS+DB
而这里介绍的MySQL属于一个数据库管理系统(DBMS),与其相同的主流数据库管理系统还有:Oracle、SQL server等

关系型数据库

概念:建立在关系模型上,由多张相互连接的二维表组成的数据库。
特点:(1)使用表存储数据,格式统一,便于维护。(2)使用统一的SQL语句操作。

SQL语句及其分类

通用语法

(1)SQL语句可以单行或者多行书写,以分号结尾。
(2)SQL语句可以使用空格?缩进来增强语句的可读性
(3)MySQL数据库的SQL语句不区分大小写,关键字建议使用大写
(4)注释:单行注释 --或# 多行注释/* */

SQL语句分类

(1)DDL(Data Definition Language)数据定义语言:用来定义数据库对象(数据库,表,字段)
(2)DML(Data Maniputation Language)数据操作语言:用来对数据库表中的数据进行增删改
(3)DQL(Data Query Language)数据查询语言:用来查询数据库中表的记录
(4)DCL(Data Control Language)数据控制语言:用来创建数据库用户、控制数据库的访问权限

数据类型

在MySQL中,类似其他语言一样,也提供了一些数据类型,这里只介绍几种常用的数据类型

字符串类型

(1)CHAR(定长字符串)
(2)VARCHAR(变长字符串)
CHAR的性能好,VARCHAR性能较差

数值类型

(1)TINYINT (小整数值)
(2)SMALLINT(大整数值)
(3)MEDIUMINT(大整数值)
(4)INT(大整数值)
(5)FLOAT(单精度浮点数)
(6)DOUBLE(双精度浮点数)
(7)DECIMAL(小精度,精确定点数)

日期类型

(1)DATE (XXXX-XX-XX)日期类型
(2)TIME (HH:MM:SS)时间类型
(3)YEAR (YYYY)年份

Data Definition Language(DDL)

1.查询所有数据库
show databases;
2.查询当前所在的数据库
select database();
3.创建数据库
create database [if not exists] 数据库名 [default charset 字符集] [collate 排序规则]
4.删除数据库
drop database[if exists] 数据库名
5.使用数据库
use 数据库名
6.查询当前数据库所有表
SHOW TABLES;
7.查询表结构
desc 表名
8.查询指定表的建表语句
show create table 表名;
9.创建表

create table 表名(
字段名1 类型名  comment 字段注释,
字段名2 类型名  comment 字段注释,
...
字段名n 类型名  comment 字段注释);
-- 注意,最后一个字段结尾不要符号

10.添加字段
alter table 表名 add 字段名 字段类型 [comment 注释];
11.修改表中字段的数据类型
alter table 表名 modify 字段名 新数据类型
12.修改表中字段名和字段的数据类型
alter table 表名 change 旧字段名 新字段名 新字段类型
13.删除字段
alter table 表名 drop 字段名
14.更新表名称
alter table 表名 rename to 新表名
15.删除表
DROP TABLE[IF EXISTS] 表名称
16.删除表并重新创建该表
TRUNCATE TABLE 表名称
方法主要是将表中数据清空

DDL语言练习

在这里插入图片描述

create table emp(
id int comment '编号',
workno varchar(10) comment '姓名',
name varchar(10) comment '姓名',
gender char(1) comment '性别',
age int comment '年龄',
idcard char(18) comment '身份证号',
entry_date date comment'入职时间'
)comment '员工信息表';

Data Manuscript Language(DML)

数据操作语言,主要是往二维表里面进行增删改的操作,主要设计以下三个关键字,insert、delete、update
1.添加数据

-- 按字段添加
insert into 表名(字段列表) values(1,2...);
-- 全部字段添加  要求值和表的字段顺序一一对应
insert into 表名 values(1,2...);
-- 批量添加数据
INSERT INTO 表名 VALUES(1,2,...),(1,2,...);

2.修改数据
update 表名 set 字段1=值1,字段2=值2,...[where 条件]
3.删除数据
delete from 表名[where 条件]
delete 只能删除行数据,并不能删除某个字段,如果需要删除某个字段的值,使用UPDATE将其设置为NULL即可。

Data Query Language(DQL)

案例基于前面DDL例题的emp表。数据如下在这里插入图片描述

基本查询

(1) 查询多个字段 select 字段1,字段2 from 表名
例:从emp表里查询id和name字段数据
select id ,name from emp;
在这里插入图片描述
(2)查询所有字段,使用通配符*
select * from 表名
例:查询emp表所有员工信息

select * from emp

在这里插入图片描述
(3)为查询字段设置别名,主要是查询后返回结果会直接和我们设置查询的字段一致,例如select后接一个较为复杂的函数,那么这个函数也会显示在查询后的结果的列名字段内。可以使用如下语法修改查询字段别名。
select 字段1 [as] 别名,字段2 [as] 别名 from 表名其中as可以省略
例:在emp表查询id和name字段,分别取别名为:编号、姓名

select id '编号',name '姓名' from emp;

在这里插入图片描述
(4)去除重复记录,使用distinct关键字即可
select distinct 字段名 from 表名
例:查看该公司这么多名员工一共有多少岗位?(需对结果去重)

select  distinct job from emp;

在这里插入图片描述

条件查询

语法:select 字段列表 from 表名 where 条件
条件主要包括比较运算和逻辑运算: > 、 < 、 > = 、 < = 、 = 、 < > >、<、>=、<=、=、<> ><>=<==<> ! = 、 B E T W E E N . . . A N D . . . 、 I N ( 列表值 ) \rm !=、BETWEEN...AND...、IN(列表值) !=BETWEEN...AND...IN(列表值) L I K E \mathrm{LIKE} LIKE占位符(_匹配一个字符,%匹配任意字符), I S N U L L \mathrm IS NULL ISNULL或者逻辑与或非
例1:查找所有年龄大于30岁的员工信息。

select * from emp where age>30;

在这里插入图片描述
例2:查询在20到30岁之间员工的信息(包含20岁和30岁)

-- 方式1,使用>和<以及逻辑与
select * from emp where age>=20 and age<=30;
-- 方式2,使用between...and...语句
select * from emp where age between 20 and 30;

在这里插入图片描述
例3.查询年龄为22岁、25岁和35岁的员工。(in关键字)

select * from emp where age in(22,25,35);

在这里插入图片描述
例4.查询2023年7月份入职的员工姓名和岗位以及具体入职时间。(like关键字)

select name '姓名',job '岗位', entry_date '入职时间' 
from emp 
where entry_date like '2023-07-%';

在这里插入图片描述
例5.查询直系领导id(manager_id)为空的人的相关信息

select * from emp where manager_id is null;

在这里插入图片描述

聚合函数

聚合函数主要将一列数据看做一个整体,进行纵向计算。
(1)count:统计数量
(2)max:最大值
(3)min:最小值
(4)avg:平均数
(5)sum:求和
SELECT 聚合函数(字段列表) FROM 表名;
例1. 统计年龄在30岁以上的人数

select count(*) '人数' from emp where age>30;

在这里插入图片描述
例2.获取年龄的最大值和最小值、平均值和总和。

select max(age) '最大年龄', min(age) '最小年龄', avg(age)'平均年龄',sum(age) '年龄总和' from emp;

在这里插入图片描述

分组查询

分组查询指的是按照某个字段进行分组后再进行查询,一般分组查询都和聚合函数连用,如果要对分组后的条件进行过滤,需要使用Having关键字。
select 字段列表 from 表名 [where 条件] group by 分组字段 having 分组后筛选条件
这里有两个条件句,一个是where,一个是having。区别如下:
(1)where是在分组之前进行过滤,不满足where条件的数据不参与分组,而having是分组之后过滤
(2)where不能对聚合函数进些判断,而having可以。
例1:现在已经对emp表中人员添加性别字段gender,根据性别统计男女生的人数。(聚合函数+分组查询)表的数据如下在这里插入图片描述

select gender,count(*) '人数' from emp group by gender;

在这里插入图片描述

排序查询

有时候,需要对查询的结果进行排序。可以使用order by 关键字
select 字段列表 from 表名 [where 条件] [group by 分组列表] order by 字段1[asc|desc],字段2[asc|desc]
在排序后面有asc和desc,asc表示按照排序列表升序排列,desc则表示按照排序字段降序排列。默认的是asc,所以如果是升序排列,asc可以省略不写。而对于字段的顺序也有严格要求,先按照字段1的规则进行排序,若两条记录在该字段上相同,则按照字段2的规则进行排序。
例题:对emp表进行排序,先按照部门id升序排序,如果相同则按照年龄降序排序。

select name '姓名',dept_id '部门ID',age '年龄' from emp order by dept_id asc,age desc ;

在这里插入图片描述

分页查询

SELECT 字段列表 FROM 表名 LIMIT 起始索引,查询记录数;
起始索引从零开始,起始索引=(查询页码-1)×每一页的显示记录数
例:展示上面排序查询的例题结果的前5条记录

select name '姓名',dept_id '部门ID',age '年龄' from emp order by dept_id asc,age desc limit 1,5 ;

在这里插入图片描述

总结DDL

在这里插入图片描述

Database Control Language(DCL)

DCL是数据控制语言,主要负责管理数据库用户,控制数据库的访问权限,一般开发人员涉及的较少,了解即可。

用户管理

(1)查询用户
首先要知道,用户信息存储在系统的mysql数据库的user表内。所以先使用该数据库,再查询该表即可。

use mysql;
select * from user;

在这里插入图片描述

下面介绍一些常用的指令,不再一一演示。
(2)创建用户:CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
(3)修改密码:ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY'新密码'
(4)删除用户:DROP USER '用户名'@'主机名'

权限管理

主要使用以下权限:ALL、ALL PRIVILEGES;SELECT;INSERT;UPDATE;DELETE;ALTER;DROP;CREATE;
(1)查询权限:SHOW GRANTS FOR '用户名'@'主机名';
(2)授予权限:GRANT 权限列表 on数据库名.表名 TO '用户名'@'主机名';
(3)撤销权限:REVOKE 权限列表 on 数据库名.表名 FROM '用户名'@'主机名';

函数

函数指的是系统提供的一些处理数据的已封装好的程序,主要可以分为字符串函数、数值函数、日期型函数、流程控制类函数四类。下面对其常用的方法进行描述。

字符串函数

(1)concat(s1,s2,...sn) 字符串拼接,将s1,s2,…sn进行拼接

select concat('hello',' mysql','!');
-- 返回:hello mysql!

(2)lower(str)将字符串str转换成小写

select lower('HELlo!');
-- 返回:hello!

(3)upper(str)将字符串str转换成大写

select upper('HELlo!');
-- 返回:HELLO!

(4)lpad(str,n,pad) 左填充,用字符串pad对str左边进行填充,达到n个字符串长度

select lpad('01', 5, '-');
-- 返回:---01

(5)rpad(str,n,pad)右填充,用字符串pad对str右边进行填充,达到n个字符串长度

select rpad('01', 5, '-');
-- 返回:01---

(6)trim(str)去除字符串开头和结尾的空格

select trim(' Hello MySQL!  ');
-- 返回:Hello MySQL!

(7)substring(str,start,len) 在字符串str的start位置截取len长度的字符串(下标从1开始)

`select substring('hello mysql',1,5);`
-- 返回:hello

(8)substring_index(str, delim, count)str:要处理的原始字符串 delim:分隔符 count:指定返回的子串位置

select substring_index('185cm/t70kg/tmale', '/t', -1);
-- 返回:male

例题1:在之前的emp表中,可以发现id为1位或者2位数,现在由于人员激增,需要将其统一设置成5为id,不足5位的在其前面补0

-- 这是一个修改语句,使用update
update emp set id=lpad(id,5,0);

执行前:
在这里插入图片描述
执行后:
在这里插入图片描述

数值函数

(1)ceil(x)向上取整

select ceil(1.01);
-- 返回:2

(2)floor(x)向下取整

select floor(1.99);
-- 返回:1

(3)mod(x,y)返回x/y的模

select mod(5,2);
-- 返回:1

(4)rand()返回0~1内的随机数

select rand();
-- 返回随机数,每次执行结果都不一样

(5)round(x,y)返回x的四舍五入结果,保留y位小数

select round(4.256,2);
--返回: 4.26

例题2:现在模仿验证码程序,生成一个6位随机验证码

-- 方法1:利用rand()和substring()
select substring(rand(),3,6);  -- 从第三位(小数点算一位)开始截取六位
-- 方法2:利用rand()和lpad()以及取整函数,这里选择ceil
select lpad(ceil(rand()*1000000),6,0);

日期型函数

(1)curdate()返回当前日期

select curdate();
-- 返回:当前日期YYYY-MM-DD,例如:2025-04-29

(2)curtime()返回当前时间

select curtime();
-- 返回:当前时间HH:MM:SS,例如:17:35:38

(3)now()返回当前日期+时间
(4)year(date)返回date的年份
(5)month(date)返回date的月份
(6)day(date)返回date的日期
(7)date_add(date,interval expr type) 返回一个日期/时间值加上一个时间间隔expr后的日期值

select date_add(curdate(),interval 10 day);  -- 查看往后10天是几月几号
select date_add(curdate(),interval 10 month); -- 查看往后10个月是几月几号
select date_add(curdate(),interval 10 year); -- 查看往后10年是几月几号

(8)datediff(date1,date2)返回两个时间差的天数

select datadiff(curdate(), '2025-01-01');  -- 查询今天和2025年1月1日时间差的天数

流程控制类函数

(1)if(value,t,f) 如果value为true,则返回t,否则返回false

select if(true, 'ok', 'error');  -- 返回'ok'
select if(false, 'ok', 'error'); -- 返回'error'

(2)ifnull(value1, value2) 如果value1不为空则返回value1,否则返回value2

select ifnull('OK', 'Default');  -- 返回'OK'
select ifnull(null, 'Default');  -- 返回'Default'

(3)case when[val1] then[res1] else [default] end如果val1为true,返回res1,否则返回default默认值
(4)case[expr] when [val1] then[res1] else [default] end如果expr的值为val1,返回res1,否则返回default默认值
(3)(4)类似,在这里主要举例介绍(3)
例题3:在emp表中,有一列salary表示员工薪水,现在对其进行评级,规则如下:
salary<=3000为1级
3000<salary<=8000为2级
8000<salary<=15000为3级
15000<salary<=30000为4级
salary>30000为5级。
现需要查询出员工的姓名,薪资和对应的等级,并取别名。

select
    name '姓名',
    salary '薪水',
    case when salary<=3000 then '1级' when salary<=8000 then '2级' when salary<=15000 then '3级' when salary<=30000 then '4级' else '5级'  end '薪资水平'
from emp;

在这里插入图片描述

约束

约束分类

概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。
目的:保证数据库中数据的正确、有效性和完整性。

约束描述关键字
非空约束限制该字段的数据不能为nullNOT NULL
唯一约束保证该字段的所有数据唯一、不重复UNIQUE
主键约束主键是一行数据的唯一标识,要求非空且唯一PRIMARY KEY
默认约束保存数据时,如果未指定该字段的值,则采用默认值DEFAULT
检查约束保证某一个字段满足条件CHECK
外键约束用来让两张表的数据之间建立连接,保证数据的一致性和完整性FOREIGN KEY

注释:当插入失败的时候,主键自动增长还是会执行,这是因为该操作已经向数据库申请了一个主键。

外键

外键约束主要是让两张表之间建立连接,从而保证数据之间的完整性。一个表中,如果有一个键是其他表的主键,那么这个键就是该表的一个外键。其中,具有外键的表称之为子表(从表),原表称之为父表(主表)
(1)创表的时候添加外键
create table 表名 (字段名 数据类型... constraint [外键名称] foreign key(外键字段名) reference 主表(主表字段名));
(2)已有的表上添加外键
alter table 表名 add constraint 外键名称 foreign key(外键字段名) references 主表(主表列名);
(3) 删除外键
alter table 表名 drop foreign key 外键名称
例:创建如下两张表,部门表dept,主要包括以下字段:

dept表字段说明
id部门编号,整数类型,设置为主键且可以自动增加键值(auto_increment)
name部门名称,varchar类型,不能为空
建表并插入5个数据
-- 创建dept并插入数据
create table dept(
    id int primary key auto_increment comment 'ID',
    name varchar(10) not null comment '部门名称')comment '部门表';
insert into dept (id, name) VALUES (1,'研发部'),(2,'市场部'),(3,'财务部'),(4,'销售部'),(5,'总经办');

员工表emp,主要字段说明如下:

emp表字段字段说明
id员工编号,整数类型,设置为主键且可以自动增加键值
name姓名,varchar类型,不能为空
age年龄,整数类型
job职位,varchar类型
salary薪资,整数类型
entry_date入职时间,date类型
manager_id直系领导ID,整数类型
dept_id部门编号,整数类型

这里的dept_id是dept这张表的主键,所以他需要设置为外键,以保证数据的完整性和统一性。

-- 建表并插入数据
create table emp(
    id int auto_increment comment 'ID' primary key ,
    name varchar(50) not null comment '姓名',
    age int comment '年龄',
    job varchar(20) comment '职位',
    salary int comment '薪资',
    entry_date date comment '入职时间',
    manager_id int comment '直属领导ID',
    dept_id int   comment '部门ID',
    constraint fk_emp_dept foreign key(dept_id) references dept(id)
)comment '员工表';
INSERT INTO emp (name, age, job, salary, entry_date, manager_id, dept_id) VALUES
('张伟', 45, 'CEO', 50000, '2015-06-15', NULL, 1),
('李娜', 38, '技术总监', 30000, '2017-03-22', 1, 2),
('王强', 28, '高级工程师', 20000, '2019-08-10', 2, 2),
('赵敏', 25, 'UI设计师', 15000, '2021-04-12', 2, 3),
('陈芳', 32, '财务经理', 25000, '2018-11-18', 1, 4),
('周杰', 30, '销售总监', 28000, '2020-05-30', 1, 5),
('林小新', 22, '实习生', 5000, '2023-07-15', 3, 2),
('吴刚', 35, '产品经理', 23000, '2019-02-14', 1, 3),
('郑爽', 27, '市场专员', 18000, '2021-09-01', 6, 5),
('刘建国', 59, '技术顾问', 32000, '2010-10-10', 1, 2),
('张无忌',28,'运维',5500, '2022-05-21', null, 1),
('李浩',22,'实习生',5000,'2023-07-15',3,2),
('刘峰',33,'产品经理',33000,'2021-09-01',1,3);

外键绑定后,如果要删除主表的数据,从表会如何操作,有以下行为可以选择

行为说明
NO ACTION当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。(与RESTRICT一致)
RESTRICT当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。(与NOACTION一致)
CASCADE当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录。
SET NULL当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为null(这就要求该外键允许取null)。
SET DEFAULT父表有变更时,子表将外键列设置成一个默认的值(Innodb存储引擎不支持)

其具体的修改语法如下:
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY(外键字段名) REFENENCE 主表(主表主键名)ON UPDATE 行为关键词 ON DELETE行为关键词来定义更新和删除的时候对应的行为,其中,NO ACTION和RESTRICT是默认的。即如果表A关联了表B的主键,即表A设立一个外键,那么如果在表B上删除某条记录的时候,先去检查表A上是否有记录关联该字段,如果有,则无法删除,没有则可以删除。下面举例演示

insert into dept(id, name) values (6,'摸鱼部');
delete from dept where id=6;
-- 新增“摸鱼部”,但是emp表中没有部门为6的员工,所以删除不会报错

删除在emp表有记录的dept对应记录

delete from dept where id=5;

在这里插入图片描述
可以看到这里报错,无法进行删除。

多表查询

多表关系

多个表之间可能存在以下三种关系
(1)一对多(多对一)
案例:部门和员工的关系
关系:一个部门对应多个员工,而一个员工对应一个部门
实现:在多的一方建立外键,指向一的一方的主键,即在员工表设立一个外键指向部门表的主键
(2)多对多
案例:学生和课程的关系
关系:一个学生可以选修多门课程,一门课程可以被多名学生选修
实现:建立一个中间表,中间表必须包含两者的主键
(3)一对一
案例:用户与用户详情的关系
关系:一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表上,以提升操作效率
实现:在任意一方加入外键,关联另一方的主键,并将外键设置成唯一的(UNIQUE)

笛卡尔积:在数学中,笛卡尔积指的是两个集合A和集合B所有组合情况。
例如,在之前的员工表和部门表中,查询其笛卡尔积的员工姓名和部门名称如下:

select emp.name,dept.name from emp,dept;

在这里插入图片描述
一共有13名员工,5个部门,所以笛卡尔积的结果数量为 13 × 5 = 65 ( 条 ) 13\times5=65(条) 13×5=65()记录。所以在多表查询的时候,需要消除掉无效的笛卡尔积。

多表连接分类

(1)内连接:查询多表的交集部分

(a)隐式内连接:select 字段列表 from 表1,表2 where 多表连接条件

-- 同样是上述案例
select emp.name,dept.name from emp,dept where dept_id=dept.id;
select e.name,d.name from emp e,dept d where e.dept_id=d.id;

(b)显式内连接:select 字段列表 from 表1 [inner] join 表2 on 条件;

select emp.name,dept.name from emp join dept on emp.dept_id = dept.id;

上述查询结果如下:
在这里插入图片描述

(2)外连接

(1)左外连接:查询结果包含左表的全部内容和两张表的交集部分
语法:select 字段列表 from 表1 left join 表2 on 条件;
(2)右外连接:查询结果包含右表的全部内容和两张表的交集部分
语法:select 字段列表 from 表1 right join 表2 on 条件;

-- 查询emp表的所有数据,和对应的部门信息(左外连接)
select emp.*,dept.name from emp left join dept on dept_id=dept.id;
-- 右外连接
select emp.*,dept.* from emp right join dept on dept_id=dept.id;

在这里插入图片描述
一般来说,右外连接能实现的功能,左外连接都能实现,主要就是将表1和表2的顺序对调后替换关键字right为left即可。

(3)自连接

当前表与自身的连接查询,自连接必须使用表别名
语法:SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON条件

-- 查询员工及其所属领导的名字
-- 分析:只能查到员工的直属领导ID,而ID对应的名字也在emp表中,所以这时就需要使用自连接
-- 条件:直系领导的ID(manager_id)等于员工表emp的ID
select a.name '员工姓名', b.name '直系领导姓名' from emp a join emp b on a.manager_id=b.id;

在这里插入图片描述

-- 查询员工及其所属领导的名字,若没有所属领导,也要显示出来
select a.name '员工姓名', b.name '直系领导姓名' from emp a left join emp b on a.manager_id=b.id;

在这里插入图片描述

子查询

SQL语句中嵌套的SELECT语句,称为嵌套查询,又称子查询。
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
子查询外部的语句可以使INSERT、UPDATE、DELETE、SELECT任意一种。根据子查询的结果,子查询可以分为:标量子查询、列子查询、行子查询、表子查询

(1)标量子查询

子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。子查询常用的操作符有:=;<>;>;>=;<;<=

-- 查询“市场部”所有员工的信息
-- 先在部门表查出“市场部”的部门ID,再在员工表找出ID与之匹配的。
select * from emp where dept_id=(select id from dept where name='市场部');

在这里插入图片描述

-- 查询在'陈芳'入职之后的员工姓名、年龄和入职日期;
-- 先在emp查到‘陈芳’的入职信息,再在员工表找到入职日期大于该日期的员工
select name,age,entry_date from emp where entry_date>(select entry_date from emp where name='陈芳');```

在这里插入图片描述

(2)列子查询

子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。常用操作符:IN,NOT IN,ANY,ALL,SOME(any和some一样)

操作符描述
IN在指定的集合范围内,多选一
NOT IN不在指定的集合范围内
ANY子查询的返回列表中,有任意一个满足要求即可
SOME与ANY等价,可以互换
ALL子查询返回列表的所有值都必须满足
-- 1.查询‘销售部'和'市场部'的所有员工信息
select * from emp where dept_id in (select id from dept where name='销售部' or name='市场部');

在这里插入图片描述

-- 2.查询比'财务部'所有人薪资都高的员工信息
select * from emp where salary>all(select salary from emp where dept_id=(select id from dept where name='财务部'));

在这里插入图片描述

-- 3.比研发部任意一人薪资都高的员工信息
select * from emp where salary>any(select salary from emp where dept_id=(select id from dept where name='研发部'));;

在这里插入图片描述

(3)行子查询

子查询返回的结果是一行(可以是多列),这种子查询称为行子查询

-- 查询与‘李浩'的薪资和直属领导相同的员工信息
select * from emp where (salary,manager_id)=(select salary,manager_id from emp where name='李浩');
-- 注意多列之间判断是否相等需要使用括号

在这里插入图片描述

(4)表子查询

子查询返回的结果是一个表,这种子查询称为表子查询,常用操作符:IN

-- 查询与'李浩',‘刘峰'的职位和薪资相同的员工信息
select * from emp where (salary,manager_id) in (select salary,manager_id from emp where name='李浩' or name='刘峰');

在这里插入图片描述

联合查询UNION、UNION ALL

对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。
SELECT 字段列表 FROM 表A UNION[ALL] SELECT 字段列表 FROM 表B;
union all 就是直接将结果合并,union会进行去重

-- 查找年龄在20-30岁之间(含端点)或薪资少于20000的员工信息,不去重。
select * from emp where salary<20000 union all select * from emp where age between 20 and 30;

在这里插入图片描述
可以发现上面有重复数据,如果使用union可以完成去重。

-- 查找年龄在20-30岁之间(含端点)或薪资少于20000的员工信息,去重。
select * from emp where salary<20000 union  select * from emp where age between 20 and 30;
-- 方法二
select * from emp where salary<20000 or age between 20 and 30;

在这里插入图片描述

事务(重点、难点)

事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作看做一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。(默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。)

事务操作

(1)查看事务的提交方式
select @@autocommit;
MySQL数据库默认开启
在这里插入图片描述
(2)设置事务的提交方式
set @@autocommit=0 0为手动提交,1为自动提交
(3)提交事务
如果设置为手动提交,则每次执行完一个SQL语句后,还需要加上提交事务语句。
commit;
(4)回滚事务
如果事务执行过程出错,那么就需要进行回滚,保证数据的正确性和一致性。
rollback;
(5)开启事务
可以通过之前的事务提交方式设置事务为手动提交,也可以通过开启事务来确定一条SQL执行后不会立马提交,语句如下:
start transaction begin

事务的四大特性(ACID)

(1)原子性(Atomicity):事务是不可分割的最小单元,要么全部成功,要么全部失败。
(2)一致性(Consistency):事务完成时,必须使所有数据一致。
(3)隔离性(Isolation):数据库提供隔离机制,防止并非事务之间相互影响。
(4)持久性(Durability):事务一旦提交或者回滚,对数据库的改变是永久的。

并发事务的问题&隔离级别

在上面的三大特性中的隔离性中,提到数据库中提供隔离机制,防止并发事务之间相互影响,那么并发事务之间可能存在哪些问题呢?主要有以下三类。

问题描述
脏读一个事务读到另一个事物还未提交的数据
不可重复读一个事务先后读取同一条记录,但两次读取的数据不同
幻读一个事务读取某一个记录时,没有对应的数据行,但是往里插入的时候,显示这个数据已经存在

为了解决并发事务的问题,数据库提供了隔离机制,即事务可以设置隔离级别。

隔离级别脏读不可重复读幻读
read uncommitted
read committed×
repeatable read(默认)××
Serializable×××

可以发现,从上往下,隔离级别越来越高,但是性能越来越差。下面阐述如何设置事务的隔离级别:
查询事务的隔离级别:select @@ transaction_isolation
设置事务的隔离级别:set[session|global] transaction isolation level[Read uncommitted|Read committed|Repeatable Read(默认)|Serializable]
下面根据阐述的隔离机制演示上述的三个并发事务问题,这里以银行存款取款为例,使用下列语句建表:

create table account(
    id int primary key auto_increment comment '编号',
    name varchar(20) comment '姓名',
    money int comment '存款'
)comment '银行账户表';
insert into account(id, name, money) values
                                         (1,'张三',2000),
                                         (2,'李四',2000);

表格如下:
在这里插入图片描述
用两个命令行(cmd)作为两个事务,模仿并发事务
(1)脏读:一个事务读到另一个事务未提交的数据。
脏读
(2)不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同。
不可重复读修改隔离权限为repeatable read,可以避免不可重复读的问题
在这里插入图片描述

(3)幻读:一个事务读取某一个记录时,没有对应的数据行,但是往里插入的时候,显示这个数据已经存在
在这里插入图片描述
幻读现象的避免,使用Serializable隔离级别,该级别也称为“串行化隔离级别”,即将并行的事务如果操作同一个表格的话,会将后执行的事务进行阻塞,等待前一个事务完成,虽然避免了幻读,但是导致吞吐量降低(执行效率下降)。

在这里插入图片描述
在这里插入图片描述
以上,就是MySQL入门篇的全部知识,主要是看链接课程自学后总结的。主要包括:数据库的创建、表的增删改查、常用的四类函数(字符型函数、数值函数、日期函数、流程函数)、多表查询(表的连接)、约束以及事务。后续将更新进阶篇相关知识,例如存储引擎、索引、SQL优化等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值