通用语法及分类
分类 | 全称 | 说明 |
DDL | Data Definition Language | 数据定义语言 |
DML | Data Manipulation Language | 数据操作语言 |
DQL | Data Query Language | 数据查询语言 |
DCL | Data Control Language | 数据控制语言 |
DDL
数据库操作
查询所有数据库:
show databases;
创建数据库:
create database if not exists [数据库名];
删除数据库:
drop database if exists [数据库名];
查询当前数据库:
select database();
表操作
查询当前数据库所有表:
show tables;
创建表:
mysql> create table tb_user(
-> id int comment '编号',
-> name varchar(50) comment '姓名',
-> age int comment '年龄',
-> gender varchar(4) comment '性别'
-> ) comment '用户表';
create table score(
id int auto_increment,
name varchar(30) comment '姓名',
chinese int comment '语文成绩',
math int comment '数学成绩',
english int comment '英语成绩',
primary key (id)
) comment = '成绩表';
查询表结构:
DESC [表名];
或者:
show create table [表名];
添加字段:
ALTER TABLE [表名] ADD [字段名] 类型(长度) COMMENT '注释';
例如:ALTER TABLE employee ADD nickName varchar(20) comment '昵称';
修改字段:
1.修改数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
例如:
ALTER TABLE employee MODIFY name varchar(30);
2.修改字段名和字段类型
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束];
例如:
ALTER TABLE employee CHANGE nickName username varchar(30) COMMENT '用户名';
删除字段:
ALTER TABEL 表名 DROP 字段名;
例如:
ALTER TABLE employee DROP username;
修改表名:
ALTER TABLE 表名 RENAME TO 新表名;
例如:
ALTER TABLE employee RENAME TO emp;
删除表:
1.删除表
DROP TABLE [IF EXISTS] 表名;
例如:
DROP TABLE IF EXISTS tb_user;
2.删除指定表,并重新创建该表(原表数据会全部清空,只留下表结构)
TRUNCATE TABLE 表名;
例如:
truncate table emp;
DML
添加数据
1.给指定字段添加数据:
INSERT INTO 表名(字段名1,字段名2,...)VALUES (值1,值2,...);
2.给全部字段添加数据:
INSERT INTO 表名 VALUES (值1,值2,...);
修改数据
UPDATE 表名 SET 字段名1 = 值1,字段名1 = 值2,... WHERE 条件;
例如:
update emp SET employeeId = '957',name = '腿哥' WHERE ID = 1;
删除数据
DELETE FROM 表名 WHERE 条件;
例如:
DELETE FROM emp WHERE AGE = 24;
DQL
基础查询
SELECT * FROM 表名;
例如:select * from emp;
SELECT 字段1,字段2,... FROM 表名;
例如:SELECT NAME,AGE FROM emp;
SELECT 字段1 AS 别名 FROM 表名;(AS可省略)
例如:select employeeid '职业id' from emp;
条件查询
SELECT 字段列表 FROM 表名 WHERE 条件列表;
--查询性别为null的员工(关键字:is)
select * from emp where gender is null;
--查询年龄处于25-28的员工(关键字:and)
select * from emp where age>=25 and age<=28;
--查询性别为女且年龄为18的员工
select * from emp where gender = '女' and age = 18;
--查询年龄为18或者26的员工(关键字:in)
方式一:select * from emp where age = 18 or age = 26;
方式二:select * from emp where age in(18,26);
--查询姓名长度为2的员工(关键字:like,外加2个下划线)
select * from emp where name like '__';
--查询employeeID以'U'开头的员工(关键字:%)
select * from emp where employeeid like 'U%';
聚合函数
介绍:将一列数据作为一个整体,进行纵向计算
常见聚合函数:
函数 | 功能 |
count | 统计数量 |
max | 最大值 |
min | 最小值 |
avg | 平均值 |
sum | 求和 |
语法:SELECT 聚合函数(字段列表) FROM 表名;
注意:null值不参与所有聚合函数运算。
--统计员工数量
SELECT COUNT(*) FROM EMP;
--统计员工平均年龄
SELECT AVG(AGE) FROM EMP;
--统计员工的最大年龄
SELECT max(age) from emp;
--统计入职日期为2023年8月18日的员工年龄之和
select sum(age) from emp where hireDate = '2023-08-18';
分组查询
1.语法
SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件];
2.where与having的区别
执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;
而having是分组之后对结果进行过滤。
判断条件不同:where不能对聚合函数进行判断,而having可以。
3.例子
--1.根据性别分组查询
select gender, count(*) from emp group by gender;
--2.根据性别分组,统计各组员工的平均年龄
select gender, avg(age) from emp group by gender;
--3.查询年龄小于26,并根据入职日期分组,获取员工数量大于等于3的入职日期
select hireDate,count(*)hireDateCount from emp where age < 26 group by hireDate having hireDateCount >= 3;
排序查询
1.语法
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2;
2.例子
--1.根据年龄对员工进行升序排序
select * from emp order by age asc;
--2.根据入职时间对员工进行降序排序
select * from emp order by hireDate desc;
--3.根据年龄对员工进行降序排序,若年龄相同,再按照入职时间降序排序
select * from emp order by age desc,hireDate desc;
分页查询
1.语法
SELECT 字段列表 FROM 表名 LIMIT 起始索引,查询记录数;
其中:起始索引 = (页码 - 1)* 页展示记录数。
2.例子
--1.查询第一页员工数据,每页展示5条记录
select * from emp limit 0,5;
--2.查询第二页员工记录,每页展示5条记录
select * from emp limit 5,5;
--有limit和order by,先order by 再到 limit
select * from emp where age >23 and age <= 26 order by age asc,hireDate asc limit 0,5;
函数
字符串函数
函数 | 功能 |
concat(s1, s2, ... sn) | 字符串拼接,将s1,s2,... 拼接成一个字符串 |
lower(str) | 将字符串str全部转为小写 |
upper(str) | 将字符串str全部转为大写 |
lpad(str, n, pad) | 左填充,用字符串pad对str的左边进行填充,达到n个字符串长度 |
rpad(str, n, pad) | 右填充,用字符串pad对str的右边进行填充,达到n个字符串长度 |
trim(str) | 去掉字符串头部和尾部的空格 |
substring(str, start, len) | 返回从字符串str从start位置起的len个长度的字符串 |
例子:
语法:SELECT 函数(参数);
SELECT concat('hcy-','henshuai');
+---------------------------+
| concat('hcy-','henshuai') |
+---------------------------+
| hcy-henshuai |
+---------------------------+
mysql> select lower('HCY');
+--------------+
| lower('HCY') |
+--------------+
| hcy |
+--------------+
mysql> select upper('hcy');
+--------------+
| upper('hcy') |
+--------------+
| HCY |
+--------------+
mysql> select lpad('hcy', 5, '-');
+---------------------+
| lpad('hcy', 5, '-') |
+---------------------+
| --hcy |
+---------------------+
mysql> select rpad('hcy', 5, '-');
+---------------------+
| rpad('hcy', 5, '-') |
+---------------------+
| hcy-- |
+---------------------+
mysql> select trim(' hcy hen shuai ');
+-----------------------------+
| trim(' hcy hen shuai ') |
+-----------------------------+
| hcy hen shuai |
+-----------------------------+
mysql> select substring('hello world', 1, 5);
+--------------------------------+
| substring('hello world', 1, 5) |
+--------------------------------+
| hello |
+--------------------------------+
应用案例
--将员工工号统一为9位数,不足在左边填充0
update emp set employeeId = lpad(employeeId, 9 ,0);
mysql> select * from emp;
+------+------------+----------+--------+------+--------------+------------+
| id | employeeId | name | gender | age | idCardNumber | hireDate |
+------+------------+----------+--------+------+--------------+------------+
| 1 | 000000957 | 腿哥 | 男 | 23 | 454545454545 | 2023-08-17 |
| 1 | 000000957 | 腿哥 | 男 | 23 | 454545454545 | 2023-08-17 |
| 1 | 000000957 | 腿哥 | 男 | 23 | 454545454545 | 2023-08-17 |
| 1 | 000000957 | 腿哥 | 男 | 23 | 454545454545 | 2023-08-17 |
| 1 | 000000957 | 腿哥 | 男 | 23 | 454545454545 | 2023-08-18 |
| 3 | 000000369 | 白家浩 | 男 | 25 | 008 | 2022-02-28 |
| 4 | 000000UZI | 简自豪 | 男 | 26 | 006 | 2023-08-18 |
| 5 | clearlove | 厂长 | NULL | 28 | NULL | NULL |
| 6 | 000mayumi | 马来靓女 | 女 | 18 | 818 | 2023-08-18 |
+------+------------+----------+--------+------+--------------+------------+
数值函数
函数 | 功能 |
ceil(x) | 向上取整 |
floor(x) | 向下取整 |
mod(x, y) | 返回x/y的模(可以用%表示,实际是求余数) |
rand() | 返回0~1内的随机数 |
round(x, y) | 求参数x的四舍五入的值,保留y位小数 |
应用案例
--通过数据库函数,生成一个六位数的随机验证码。
select lpad(round(rand()*1000000,0), 6, '0');
1.首先用rand()生成随机数,并*1000000;
2.用round()函数四舍五入,保留0位小数;
3.用lpad()函数对不足6位的数据在左边填充0;
日期函数
函数 | 功能 |
curdate() | 返回当前日期 |
curtime() | 返回当前时间 |
now() | 返回当前日期和时间 |
year(date) | 获取指定date的年份 |
month(date) | 获取指定date的月份 |
day(date) | 获取指定date的日期 |
date_add(date, interval expr type) | 返回一个日期/时间值加上一个时间间隔expr后的时间值 |
datediff(date1, date2) | 返回起始时间date1和结束时间date2之间的天数 |
应用案例
--date_add
mysql> select date_add(now(), interval 90 day);
+----------------------------------+
| date_add(now(), interval 90 day) |
+----------------------------------+
| 2023-11-21 14:21:40 |
+----------------------------------+
--datediff
mysql> select datediff('20230823', '20211225');
+----------------------------------+
| datediff('20230823', '20211225') |
+----------------------------------+
| 606 |
+----------------------------------+
--查询所有员工的入职天数,降序排序
select name, datediff(curdate(), hireDate) datediff from emp order by datediff desc;
+----------+----------+
| name | datediff |
+----------+----------+
| 白家浩 | 541 |
| 腿哥 | 6 |
| 腿哥 | 6 |
| 腿哥 | 6 |
| 腿哥 | 6 |
| 腿哥 | 5 |
| 简自豪 | 5 |
| 马来靓女 | 5 |
| 厂长 | NULL |
+----------+----------+
流程函数
函数 | 功能 |
if(value, t, f) | 如果value为true,则返回t,否则返回f |
ifnull(value1, value2) | 如果value1不为空,返回value1,否则返回value2 |
case when [val1] then [res1] ... else [default] end | 如果val1为true,返回res1,... 否则返回default默认值 |
case [expr] when [val1] then [res1] ... else [default] end | 如果expr的值等于val1,返回res1,... 否则返回default默认值 |
应用案例
--查询员工姓名和地址,地址按一二线城市划分。
select name, case addr when '上海' then '一线城市' when '深圳' then '一线城市'
else '二线城市' end '工作地址' from emp;
+--------+----------+
| name | 工作地址 |
+--------+----------+
| 白家浩 | 二线城市 |
| 简自豪 | 二线城市 |
| 厂长 | 一线城市 |
| 卡萨 | 一线城市 |
| 林炜翔 | 一线城市 |
| 刘青松 | 一线城市 |
| 金泰相 | 一线城市 |
| 小天 | 一线城市 |
+--------+----------+
约束
约束 | 描述 | 关键字 |
非空约束 | 限制该字段的数据不能为null。 | not null |
唯一约束 | 保证该字段的所有数据都是唯一,不重复。 | unique |
主键约束 | 主键是一行数据的唯一标识,要求非空且唯一。 | primary key |
默认约束 | 保存数据时,如果未指定该字段的值,则采用默认值。 | default |
检查约束 | 保证字段满足某一条件。 | check |
外键约束 | 用来让两张表的数据之间建立连接,保证数据的一致性和完整性。 | foreign key |
外键约束
语法-添加外键
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名) REFERENCES 主表(主表列名);
例如:
alter table emp add constraint fk_club_id foreign key (club_id) references club(id);
删除外键
ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;
例如:
alter table emp drop foreign key fk_club_id;
多表查询
多表关系介绍
一对多
案例:部门和员工的关系。
关系:一个部门对应多个员工,一个员工对应一个部门。
实现:在多的一方建立外键,指向一的一方的主键。
多对多
案例:学生和课程的关系。
关系:一个学生可以选修多门课程。一门课程也可以供多个学生选择。
实现:建立第三张中间表,中间表至少包含两个外键,分别关联两房主键。
一对一
案例:用户和用户详情的关系。
关系:一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率
实现:在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)。
内连接
隐式内连接
SELECT 字段列表 FROM 表1,表2 WHERE 条件;
显式内连接
SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件;
例子
--查询员工姓名,以及关联的部门名称(隐式内连接实现)
mysql> select emp.name,club.name from emp,club where emp.club_id = club.id;
+--------+------+
| name | name |
+--------+------+
| 白家浩 | JDG |
| 简自豪 | EDG |
| 厂长 | EDG |
| 卡萨 | WBG |
| 刘青松 | WBG |
| 林炜翔 | FPX |
| 金泰相 | LNG |
| 小天 | TOP |
+--------+------+
--查询员工姓名,以及关联的部门名称(显式内连接实现)
mysql> select emp.name,club.name from emp inner join club on emp.club_id = club.id;
+--------+------+
| name | name |
+--------+------+
| 白家浩 | JDG |
| 简自豪 | EDG |
| 厂长 | EDG |
| 卡萨 | WBG |
| 刘青松 | WBG |
| 林炜翔 | FPX |
| 金泰相 | LNG |
| 小天 | TOP |
+--------+------+
外连接
左外连接
SELECT 字段列表 FROM 表1 LEFT JOIN 表2 ON 条件;
右外连接
SELECT 字段列表 FROM 表1 RIGHT JOIN 表2 ON 条件;
例子
--查询员工姓名及对应俱乐部名称(左外连接)
mysql> SELECT emp.name, club.name from emp left join club on emp.club_id = club.id;
+--------+------+
| name | name |
+--------+------+
| 白家浩 | JDG |
| 简自豪 | EDG |
| 厂长 | EDG |
| 卡萨 | WBG |
| 林炜翔 | FPX |
| 刘青松 | WBG |
| 金泰相 | LNG |
| 小天 | TOP |
| 小黄人 | NULL |
+--------+------+
--查询俱乐部名称及对应的队员姓名(右外连接)
mysql> select club.name,emp.name from emp right join club on emp.club_id = club.id;
+------+--------+
| name | name |
+------+--------+
| JDG | 白家浩 |
| EDG | 简自豪 |
| EDG | 厂长 |
| WBG | 卡萨 |
| WBG | 刘青松 |
| FPX | 林炜翔 |
| LNG | 金泰相 |
| TOP | 小天 |
| DWG | NULL |
+------+--------+
自连接
自连接可以是内连接,也可以是外连接,一定要记得给表取别名。
语法
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件;
例子:
select a.name '员工', b.name '领导' from emp a left join emp b on a.managerid = b.id;
联合查询
对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。
SELECT 字段列表 FROM 表A
UNION [ALL]
SELECT 字段列表 FROM 表B;
例子
mysql> select * from emp where name like '__'
-> union
-> select * from emp where age <25;
+------+--------------+--------+--------+------+--------------+------------+------+---------+
| id | employeeId | name | gender | age | idCardNumber | hireDate | addr | club_id |
+------+--------------+--------+--------+------+--------------+------------+------+---------+
| 5 | clearlove | 厂长 | 男 | 28 | 007 | 2010-12-23 | 深圳 | 2 |
| 6 | Karsa | 卡萨 | 女 | 18 | 818 | 2023-08-18 | 上海 | 3 |
| 1 | Tian | 小天 | 男 | 24 | 013 | 2020-11-22 | 上海 | 6 |
| 1 | LWX | 林炜翔 | 男 | 22 | 888 | 2020-11-22 | 上海 | 4 |
| 7 | xiaohuangren | 小黄人 | 男 | 18 | 999 | 2023-08-25 | 广西 | NULL |
+------+--------------+--------+--------+------+--------------+------------+------+---------+
mysql> select * from emp where name like '__'
-> union all
-> select * from emp where age <25;
+------+--------------+--------+--------+------+--------------+------------+------+---------+
| id | employeeId | name | gender | age | idCardNumber | hireDate | addr | club_id |
+------+--------------+--------+--------+------+--------------+------------+------+---------+
| 5 | clearlove | 厂长 | 男 | 28 | 007 | 2010-12-23 | 深圳 | 2 |
| 6 | Karsa | 卡萨 | 女 | 18 | 818 | 2023-08-18 | 上海 | 3 |
| 1 | Tian | 小天 | 男 | 24 | 013 | 2020-11-22 | 上海 | 6 |
| 6 | Karsa | 卡萨 | 女 | 18 | 818 | 2023-08-18 | 上海 | 3 |
| 1 | LWX | 林炜翔 | 男 | 22 | 888 | 2020-11-22 | 上海 | 4 |
| 1 | Tian | 小天 | 男 | 24 | 013 | 2020-11-22 | 上海 | 6 |
| 7 | xiaohuangren | 小黄人 | 男 | 18 | 999 | 2023-08-25 | 广西 | NULL |
+------+--------------+--------+--------+------+--------------+------------+------+---------+
注意点:
1.对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
2.union all会将全部的数据直接合并在一起,union会对合并之后的数据去重。
子查询
概念:SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT中的任何一个。
根据子查询结果不同,分为:
1.标量子查询(子查询结果为单个值)
2.列子查询(子查询结果为一列)
3.行子查询(子查询结果为一行)
4.表子查询(子查询结果为多行多列)
根据子查询位置,分为:
where之后;
from之后;
select之后。
标量子查询
--查询俱乐部为WBG的员工信息
step1: select id from club where name = 'WBG'
step2: select * from emp where club_id = 3;
select * from emp where club_id = (select id from club where name = 'WBG');
--查询在369选手之后入职的员工信息
step1:select hireDate from emp where name = '白家浩';
step2:select * from emp where hireDate > '2022-02-28';
mysql> select * from emp where hireDate > (select hireDate from emp where name = '白家浩');
+------+--------------+--------+--------+------+--------------+------------+------+---------+
| id | employeeId | name | gender | age | idCardNumber | hireDate | addr | club_id |
+------+--------------+--------+--------+------+--------------+------------+------+---------+
| 4 | UZI | 简自豪 | 男 | 26 | 006 | 2023-08-18 | 湖北 | 2 |
| 6 | Karsa | 卡萨 | 女 | 18 | 818 | 2023-08-18 | 上海 | 3 |
| 7 | xiaohuangren | 小黄人 | 男 | 18 | 999 | 2023-08-25 | 广西 | NULL |
+------+--------------+--------+--------+------+--------------+------------+------+---------+
--查询各个俱乐部信息,并统计俱乐部人数
mysql> select c.id, c.name,(select count(*) from emp e where e.club_id = c.id) '人数' from club c;
+------+------+------+
| id | name | 人数 |
+------+------+------+
| 1 | JDG | 1 |
| 2 | EDG | 2 |
| 3 | WBG | 3 |
| 4 | FPX | 1 |
| 5 | LNG | 1 |
| 6 | TOP | 1 |
| 7 | DWG | 0 |
+------+------+------+
列子查询
常用的操作符:IN, NOT IN, ANY, SOME, ALL
操作符 | 描述 |
in | 在指定的集合范围之内,多选一 |
not in | 不在指定的集合范围之内 |
any | 子查询返回列表中,有任意一个满足即可 |
some | 与any等同,使用some的地方都可以使用any |
all | 子查询返回列表的所有值都必须满足 |
例子:
--列子查询
--1.查询EDG和WBG的员工信息
--a.查询EDG和WBG的id
mysql> select id from club where name = 'WBG' or name = 'EDG';
+----+
| id |
+----+
| 2 |
| 3 |
+----+
--b.根据id信息,查询员工信息
select * from emp where club_id in(select id from club where name = 'WBG' or name = 'EDG');
--2.查询工资高于WBG所有人的员工信息
--a.查询WBG员工工资
mysql> select salary from emp where club_id = (select id from club where name = 'WBG');
+--------+
| salary |
+--------+
| 6300 |
| 11000 |
+--------+
--b.比WBG全员工资都高的员工信息
mysql> select * from emp where salary > all(select salary from emp where club_id = (select id from club where name = 'WBG'));
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
| id | employeeId | name | gender | age | idCardNumber | hireDate | addr | salary | club_id |
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
| 3 | 369 | 白家浩 | 男 | 25 | 008 | 2022-02-28 | 湖南 | 13800 | 1 |
| 1 | LWX | 林炜翔 | 男 | 22 | 888 | 2020-11-22 | 上海 | 12000 | 4 |
| 1 | Doinb | 金泰相 | 男 | 26 | 012 | 2020-11-22 | 上海 | 14000 | 5 |
| 1 | Tian | 小天 | 男 | 24 | 013 | 2020-11-22 | 上海 | 12520 | 6 |
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
--3.查询比WBG任一人工资高的员工信息
--a.查询WBG薪资
mysql> select salary from emp where club_id = 3;
+--------+
| salary |
+--------+
| 9800 |
| 11000 |
+--------+
--b.查询比WBG任一人工资高的员工信息
mysql> select * from emp where salary > any(select salary from emp where club_id = 3);
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
| id | employeeId | name | gender | age | idCardNumber | hireDate | addr | salary | club_id |
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
| 3 | 369 | 白家浩 | 男 | 25 | 008 | 2022-02-28 | 湖南 | 13800 | 1 |
| 5 | clearlove | 厂长 | 男 | 28 | 007 | 2010-12-23 | 深圳 | 9801 | 2 |
| 1 | LWX | 林炜翔 | 男 | 22 | 888 | 2020-11-22 | 上海 | 12000 | 4 |
| 1 | Crisp | 刘青松 | 男 | 26 | 777 | 2020-11-22 | 上海 | 11000 | 3 |
| 1 | Doinb | 金泰相 | 男 | 26 | 012 | 2020-11-22 | 上海 | 14000 | 5 |
| 1 | Tian | 小天 | 男 | 24 | 013 | 2020-11-22 | 上海 | 12520 | 6 |
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
行子查询
子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。
常用的操作符:=,<>,IN,NOT IN。
例子:
--查询与“林炜翔”性别相同,地址相同的员工信息
--a.查询林炜翔的性别和地址
mysql> select gender, addr from emp where name = '林炜翔';
+--------+------+
| gender | addr |
+--------+------+
| 男 | 上海 |
+--------+------+
--b.查询与“林炜翔”性别相同,地址相同的员工信息
mysql> select * from emp where (gender, addr) = (select gender, addr from emp where name = '林炜翔');
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
| id | employeeId | name | gender | age | idCardNumber | hireDate | addr | salary | club_id |
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
| 1 | LWX | 林炜翔 | 男 | 22 | 888 | 2020-11-22 | 上海 | 12000 | 4 |
| 1 | Crisp | 刘青松 | 男 | 26 | 777 | 2020-11-22 | 上海 | 11000 | 3 |
| 1 | Doinb | 金泰相 | 男 | 26 | 012 | 2020-11-22 | 上海 | 14000 | 5 |
| 1 | Tian | 小天 | 男 | 24 | 013 | 2020-11-22 | 上海 | 12520 | 6 |
+------+------------+--------+--------+------+--------------+------------+------+--------+---------+
表子查询
子查询返回的结果是多行多列,这种子查询称为表子查询。
例子:
--查询与小黄人或者简自豪的性别和地址相同的员工信息
--a.查询小黄人或者简自豪的性别和地址
mysql> select gender, addr from emp where name = '小黄人' or name = '简自豪';
+--------+------+
| gender | addr |
+--------+------+
| 男 | 湖北 |
| 男 | 广西 |
+--------+------+
--b.查询与小黄人或者简自豪的性别和地址相同的员工信息
mysql> select * from emp where (gender, addr) in (select gender, addr from emp where name = '小黄人' or name = '简自豪');
+------+--------------+--------+--------+------+--------------+------------+------+--------+---------+
| id | employeeId | name | gender | age | idCardNumber | hireDate | addr | salary | club_id |
+------+--------------+--------+--------+------+--------------+------------+------+--------+---------+
| 4 | UZI | 简自豪 | 男 | 26 | 006 | 2023-08-18 | 湖北 | 9800 | 2 |
| 7 | xiaohuangren | 小黄人 | 男 | 18 | 999 | 2023-08-25 | 广西 | 8000 | NULL |
| 8 | angel | 向涛 | 男 | 22 | 676 | 2018-07-07 | 广西 | 11000 | 3 |
+------+--------------+--------+--------+------+--------------+------------+------+--------+---------+
--查询入职日期在20201122之后入职的员工信息以及部门名称
--a.查询入职日期在20201122之后入职的员工信息
select * from emp where hiredate > '20201122';
--b.查询入职日期在20201122之后入职的员工信息以及部门名称
mysql> select * from (select * from emp where hiredate > '20201122') e left join club on e.club_id = club.id;
+------+--------------+--------+--------+------+--------------+------------+------+--------+---------+------+------+
| id | employeeId | name | gender | age | idCardNumber | hireDate | addr | salary | club_id | id | name |
+------+--------------+--------+--------+------+--------------+------------+------+--------+---------+------+------+
| 3 | 369 | 白家浩 | 男 | 25 | 008 | 2022-02-28 | 湖南 | 13800 | 1 | 1 | JDG |
| 4 | UZI | 简自豪 | 男 | 26 | 006 | 2023-08-18 | 湖北 | 9800 | 2 | 2 | EDG |
| 6 | Karsa | 卡萨 | 女 | 18 | 818 | 2023-08-18 | 上海 | 9800 | 3 | 3 | WBG |
| 7 | xiaohuangren | 小黄人 | 男 | 18 | 999 | 2023-08-25 | 广西 | 8000 | NULL | NULL | NULL |
+------+--------------+--------+--------+------+--------------+------------+------+--------+---------+------+------+
多表查询例子
--查询所有学生的选课情况,展示学生姓名,学号,课程名称
--涉及到三张表,学生表,课程表,以及学生-课程关系表
mysql> select stu.name, stu.no,cour.name from stu,stu_cour,cour
where stu.id = stu_cour.stu_id and stu_cour.cour_id = cour.id;
+------+------+--------+
| name | no | name |
+------+------+--------+
| 肥春 | 001 | java |
| 肥春 | 001 | c++ |
| 肥波 | 002 | c++ |
| 肥春 | 001 | python |
| 肥波 | 002 | python |
| 肥龙 | 003 | php |
+------+------+--------+
事务
事务简介
事务是一组操作的集合,要么同时成功,要么同时失败。
事务操作
查看/设置事务提交方式
SELECT @@autocommit; --查看
SET @@autocommit = 0; --设置
开启事务
START TRANSACTION 或 BEGIN;
提交事务
COMMIT;
回滚事务
ROLLBACK;
事务四大特性(ACID)
1.原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
2.一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
3.隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
4.持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
并发事务问题
问题 | 描述 |
脏读 | 一个事务读到另一个事务还没有提交的数据。 |
不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。 |
幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了“幻影”。 |
事务隔离级别
隔离级别 | 脏读 | 不可重复度 | 幻读 |
read uncommited | √ | √ | √ |
read committed | × | √ | √ |
repeatable read(默认) | × | × | √ |
serializable | × | × | × |
.