MySQL基础
数据库相关概念
- 数据库:存储数据的仓库,数据是有组织的进行存储(DB)
- 数据库管理系统:操纵和管理数据库的大型软件(DBMS)
- SQL:操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准(SQL)
MySQL启动与停止
-
win+R输入
service.msc
,找到MySQL80
,右键启用或禁止 -
-
启动
net start mysql80
-
停止
net stop mysql80
-
-
方式一:MySQL提供的客户端命令行工具
输入密码即可进入
方式二:在提前配置PATH环境变量时
此电脑->高级->环境变量->系统变量->path->编辑->输入
mysql中的bin
的路径
使用shell在管理员模式输入
mysql -u root -p
最后输入密码即可进入
数据模型
- 关系型数据库(RDBMS)
概念:建立在关系模型基础上,有多张相互连接的二维表组成的数据库
特点:
- 使用表存储数据,格式统一,便于维护
- 使用SQL语言操作,标准统一,使用方便
SQL通用语法和语言分类
- SQL语句可以单行或多行书写,以分号结尾
- SQL语句可以使用空格/缩进来增强语句的可读性
- MySQL数据库的SQL语句不区分大小写,关键字建议使用大写
- 注释:
- 单行注释: -- 注释内容或# 注释内容(MySQL特有)
- 多行注释:/* 注释内容*/
SQL语句分类
DDL:数据定义语言,用来定义数据库对象(数据库,表,字段)
DML:数据操作语言,用来对数据库中的数据进行增删改
DQL:数据查询语言,用来查询数据库中表 的记录
DCL:数据控制语言,用来创建数据库用户、控制数据库的访问权限
DDL-数据库操作
-
查询
-
查询所有数据库
show databases;
-
查询当前数据库
select database();
-
-
创建
create database [if not exists] 数据库名 [default charset 字符集(utf8mb4)] [collate 排序规则]; -- 方括号表示可选
-
删除
DROP DATABASE[IF EXISTS]数据库名;
-
使用
use 数据库名;
DDL-表操作-查询
-
查询当前数据库所有表
SHOW TABLES;
-
查询表结构(内容)
DESC 表名;
-
查询指定表的建表语句
SHOW CREATE TABLE 表名;
DDL-表操作-创建
CREATE TABLE 表名(
字段1 字段1类型 COMMENT '姓名nsm',
......
字段n 字段n类型[COMMENT 字段n注释]
)[COMMENT 表注释];
DDL-表操作-数据类型
MySQL中的数据类型有很多,主要分为三类:数值类型、字符串类型、日期时间类型。
数值类型
MySQL 支持所有标准 SQL 数值数据类型。
这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC),以及近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。
关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词。
BIT数据类型保存位字段值,并且支持 MyISAM、MEMORY、InnoDB 和 BDB表。
作为 SQL 标准的扩展,MySQL 也支持整数类型 TINYINT、MEDIUMINT 和 BIGINT。下面的表显示了需要的每个整数类型的存储和范围。
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT | 1 Bytes | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 Bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT | 3 Bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 Bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT | 8 Bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT | 4 Bytes | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE | 8 Bytes | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
DECIMAL | 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M(精度:有效数字长)和D(标度:小数位数)的值 | 依赖于M和D的值 | 小数值(精确定点数 ) |
日期和时间类型
表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。
每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
TIMESTAMP类型有专有的自动更新特性,将在后面描述。
类型 | 大小 ( bytes) | 范围 | 格式 | 用途 |
---|---|---|---|---|
DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3 | '-838:59:59'/'838:59:59' | HH:MM:SS | 时间值或持续时间 |
YEAR | 1 | 1901/2155 | YYYY | 年份值 |
DATETIME | 8 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
TIMESTAMP | 4 | 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
字符串类型
字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255 bytes | 定长字符串 |
VARCHAR | 0-65535 bytes | 变长字符串 |
TINYBLOB | 0-255 bytes | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255 bytes | 短文本字符串 |
BLOB | 0-65 535 bytes | 二进制形式的长文本数据 |
TEXT | 0-65 535 bytes | 长文本数据 |
MEDIUMBLOB | 0-16 777 215 bytes | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215 bytes | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295 bytes | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295 bytes | 极大文本数据 |
注意:char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。
CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。
BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。
BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。
有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。
DDL-表操作-修改
- 添加字段
ALTER TABLE 表名 ADD 字段名 类型(长度)[COMMENT 注释][约束];
案例:为emp
表添加一个新字段“昵称”为nickname,类型为varchar(20)
alter table emp ADD nickname varchar(20) COMMENT '昵称';
- 修改数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
- 修改字段名和字段类型
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型(长度)[COMMENT 注释][约束];
案例:
将emp
表得到nickname字段修改为username,类型为varchar(30)
alter table emp change nickname varchar(30) COMMENT '昵称';
- 删除字段
ALTER TABLE 表名 DROP 字段名;
案例:
将emp
表的字段username删除
alter table emp drop username;
- 修改表名
ALTER TABLE 表名 RENAME TO 新表名;
- 删除表
DROP TABLE[IF EXISTS] 表名;
- 删除指定表,并重新创建该表(删除数据,但不删除表结构)
TRUNCATE TABLE 表名;
DML-添加数据
DML(数据操作语言),用来对数据库中表的数据记录进行增删改操作。
- 给指定字段添加数据
INSERT INTO 表名(字段1,字段2...) VALUES (值1,值2...);
- 给全部字段添加数据
INSERT INTO 表名 VALUES (值1,值2...);
- 批量添加数据
指定字段
INSERT INTO 表名(字段名1,字段名2...) VALUES (值1,值2...),(值1,值2),...
所有字段
INSERT INTO 表名 VALUES (值1,值2...),(值1,值2),...
注意:
- 插入数据时,指定的字段顺序需要与值的顺序是一一对应的。
- 字符串和日期数据应该包含在引导中
- 插入的数据大小,应该在字段的规定范围内。
DML-修改数据
UPDATE 表名 SET 字段名1=值1,字段名2=值2,...[WHERE 条件]
条件可有可无,但是如果没有条件,则会修改整张表的所有数据。
DML-删除数据
DELETE FROM 表名 [WHERE 条件]
- DEDLETE没有条件时会删除整张表的所有数据。
- DELETE语句不能删除某一个字段的值(可以UPDATE)
DQL-基本查询
- 查询多个字段
SELECT 字段1,字段2,... FROM 表名;
SELECT * FROM 表名;
- 设置别名
SELECT 字段1[AS 别名1],字段2[AS 别名2]... FROM 表名;-- AS可以不加,效果不变
- 去除重复记录
SELECT DISTINCT 字段列表 FROM 表名;
DQL-条件查询
- 语法
SELECT 字段列表 FROM 表名 WHERE 条件列表;
比较运算符
比较运算符 | 描述 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
= | 等于 |
<>或!= | 不等于 |
BETWEEN...AND... | 在某个范围之内(含最小、最大值) |
IN(...) | 在in之后的列表中的值满足其一即可 |
LIKE 占位符 | 模糊匹配(_匹配单个字符,%匹配任意个字符) |
IS NULL | 是NULL |
逻辑运算符
逻辑运算符 | 描述 |
---|---|
AND 或 && | 并且(多个条件同时成立) |
OR 或 || | 或者(多个条件任意一个成立) |
NOT 或 ! | 非 |
样例:
- 查询姓名为两个字得到员工信息 _
select * from emp where name like '__';-- like两个下划线
- 查询身份证号最后一位是X的员工信息
select * from emp where idcard like '%X';
DQL-聚合函数
- 介绍
将一列数据作为一个整体,进行纵向计算
- 常见聚合函数
函数 | 功能 |
---|---|
count | 统计数量 |
max | 最大值 |
min | 最小值 |
avg | 平均值 |
sum | 求和 |
- 语法
SELECT 聚合函数(字段列表) FROM 表名;
null值不参与所有聚合函数运算。
- 示例:统计西安地区员工的年龄之和(可以赋予where条件)
select sum(age) from emp where workaddress = '西安';
DQL-分组查询
1.语法
SELECT 字段列表/聚合函数 FROM 表名[where 条件] GROUP BY 分组字段名[HAVING 分组后过滤条件]
2.where与having区别
- 执行时机:where是分组之前进行过滤,不满足where条件不参与分组;而having是分组之后对结果进行过滤.
- where不能对聚合函数进行判断,但having可以
- 执行先后顺序:where,聚合函数,having(因此having可以对聚合函数进行判断)
- 分组之后,查询的字段一般为聚合函数和分组字段(表现为SELECT 、FROM之间),查询其他字段无意义(还可能会让用户感到疑惑)
3.示例
- 根据性别分组,统计男员工 和 女员工的数量
select gender,count(*) from emp group by gender;
- 查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址
select workaddress,count(*) from emp where age < 45 group by workaddress having count(*)>=3;
/*起别名,效果相同*/
select workaddress,count(*) address_count from emp where age < 45 group by workaddress having address_count>=3;
DQL-排序查询
- 语法
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1,字段2 排序方式2;
- 排序方式
- ASC:升序(默认,不必专门写代码指定)
- DESC:降序
- 如果是多字段排序,当第一个字段值排序之后,剩余相同部分使用第二个字段的要求排序
- 示例
select * from emp order by age desc; --按年龄降序
select * from emp order by age desc,workno desc; --按年龄降序,相同年龄的按工号降序
DQL-分页查询
1.语法
SELECT 字段列表 FROM 表名 LIMIT 起始索引(从0开始),查询记录数;-- limit语句一般放在所有语句之后
- 查询第n页的起始索引=(查询页码n-1) * 每页显示的记录数
- 分页查询在不同的数据库中语法不一
- 如果查询第一页数据,起始索引为0而且可以忽略。
2.示例
select * from emp limit 10;--第一页的十个记录
select * from emp limit 10,10;--第二页的十个记录
DQL-案例演示
-- 1). 查询年龄为20,21,22,23岁的女员工信息。
select * from emp where gender='女' and age in(20,21,22,23);
-- 2). 查询性别为 男 ,并且年龄在 20-40 岁(含)以内的姓名为三个字的员工。
select * from emp where gender='男' and age between 20 and 40 and name like '___';
-- 3). 统计员工表中, 年龄小于60岁的 , 男性员工和女性员工的人数。
select gender,count(*) from emp where age<60 group by gender;
-- 4). 查询所有年龄小于等于35岁员工的姓名和年龄,并对查询结果按年龄升序排序,如果年龄相同按入职时间降序排序。
select name,age from emp where age<=35 order by age,entrydate desc;
-- 5). 查询性别为男,且年龄在20-40 岁(含)以内的前5个员工信息,对查询的结果按年龄升序排序,年龄相同按入职时间升序排序。
select * from emp where gender='男' and age between 20 and 40 order by age,entrydate limit 5 ;-- limit放在最后
DQL-执行顺序
- 编写顺序
SELECT ...
FROM ...
WHERE ...
GROUP BY ...
HAVING ...
ORDER BY ...
LIMIT ...
- 执行顺序
FROM...
WHERE...
GROUP BY...
SELECT...
HAVING...
ORDER BY...
LIMIT...
DCL-管理用户
-
查询用户
select * from mysql.user;
-
创建用户(切忌重名,localhost and %对应的用户名不能重复)
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';-- 全部主机可使用设置为'用户名'@'%'
-
修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码' ;
-
删除用户
DROP USER '用户名'@'主机名';
DCL-权限控制
权限 | 说明 |
---|---|
ALL,ALL PRIVILEGES | 所有权限 |
SELECT | 查询数据 |
INSERT | 插入数据 |
UPDATE | 修改数据 |
DELETE | 删除数据 |
ALTER | 修改表 |
DROP | 删除数据库/表/视图 |
CREATE | 创建数据库/表 |
1.查询权限
SHOW GRANTS FOR '用户名'@'主机名';
2.授予权限
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';-- 权限可填all,多个权限之间可用逗号分隔, 所有数据库所有表为*.*
3.撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
函数
字符串函数
函数 | |
---|---|
CONCAT(S1,S2,S3...) | 字符串拼接,将S1,S2,S3...Sn拼接成一个字符串 |
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个长度的字符串(start从1开始) |
-- 查询用语法样例
select trim(' Hello MySQL ');-- 去除头尾空格
-- 修改用样例
update emp set workno = lpad(workno,5,'0');-- 对workno做左填充
数值函数
函数 | 功能 |
---|---|
CEIL(x) | 向上取整 |
FLOOR(x) | 向下取整 |
MOD(x,y) | 返回x/y的模 |
RAND() | 返回0~1内的随机数 |
ROUND(x,y) | 求参数x的四舍五入的值,保留y位小数 |
- 案例
通过数据库的函数,生成一个六位随机验证码
select lpad(round(rand()*100000,0),6,'0');-- 补零保留取出来是六位整数
时间函数
函数 | 功能 |
---|---|
CURDATE() | 返回当前日期 |
CURTIME() | 返回当前时间 |
NOW() | 返回当前详细时间 |
YEAR(date) | 获取date的年 |
MONTH(date) | ...月 |
DAY(date) | ...日 |
DATE_ADD(date,INTERVAL num 时间量词) | 返回一个日期/时间值加上一个时间间隔num后的时间值 |
DATEDIFF(date1,date2) | 返回date1-date2的天数 |
-- 案例:查询所有员工的入职天数,并根据入职天数倒序排序
select name,datediff(curdate(),entrydate) ENTRYDATES from emp order by ENTRYDATES desc;
流程函数
函数 | 功能 |
---|---|
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默认值 |
约束
-
概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。
-
分类:
约束 | 描述 | 关键字 |
---|---|---|
非空约束 | 限制该字段的数据不能为null | NOT NULL |
唯一约束 | 保证该字段的所有数据都是唯一、不重复的 | UNIQUE |
主键约束 | 主键是一行数据的唯一标识、要求非空,一表一主键,一主键可有多个字段 | PRIMARY KEY |
默认约束 | 保存数据时,如果未指定该字段的值,则采用的默认值 | DEFAULT |
检查约束 | 保证字段值满足某一个条件 | CHECK |
外键约束 | 让两张表的数据之间建立联系,保证数据的一致性和完整性 | FOREIGN KEY |
注意:约束是作用于表中字段上的,可以在创建表/修改时添加约束
约束演示
字段名 | 字段含义 | 字段类型 | 约束条件 | 约束关键字 |
---|---|---|---|---|
id | ID唯一标识 | int | 主键,并且自动增长 | PRIMARY KEY;AUTO_INCREMENT |
name | 姓名 | varchar(10) | 不为空,并且唯一 | NOT NULL;UNIQUE |
age | 年龄 | int | 大于0,小于等于120 | CHECK(~) |
status | 状态 | char(1) | 如果没有指定,默认为1 | DEFAULT ‘1’ |
gender | 性别 | char(1) | 无 |
有用到自增主键:唯一键冲突和事务回滚都会导致自增主键id不连续的情况,唯一键null并不会导致如此
-- 表结构
create table user(
id int primary key auto_increment comment '主键',
name varchar(10) not null unique comment '姓名',
age int check ( age>0 &&age<=120 ) comment '年龄',
status char(1) default '1' comment '状态',
gender char(1) comment '性别'
) comment '事务表';
-- 测试代码不贴了qwq
外键约束
-
外键约束 : 让两张表的数据之间建立联系,保证数据的一致性和完整性
-
语法
- 添加外键
create table 表名( 字段名 数据类型, ... [constraint] [外键名称] foreign key(要添加外键的字段名) references 父表(要建立关系的列名); );
alter table 表名 add constraint 外键名称 foreign key(同上) references 父表(同上); -- add constraint表示添加约束
- 删除外键
ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;
删除/更新行为
添加了外键之后,再删除父表数据时产生的约束行为,我们就称为删除/更新行为。具体的删除/更新行 为有以下几种:
行为 | 说明 |
---|---|
NO ACTION | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不 允许删除/更新。 (与 RESTRICT 一致) 默认行为 |
RESTRICT | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不 允许删除/更新。 (与 NO ACTION 一致) 默认行为 |
CASCADE | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则 也删除/更新外键在子表中的记录。 |
SET NULL | 当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表 中该外键值为null(这就要求该外键允许取null)。 |
SET DEFAULT | 父表有变更时,子表将外键列设置成一个默认的值 (MYSQL默认引擎Innodb不支持该功能) |
-- 更新与删除中的cascade操作
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES 主表名 (主表字段名) ON UPDATE CASCADE ON DELETE CASCADE;
-- set null操作
alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id) on update set null on delete set null ;
多表查询
多表关系
- 概述:各个表结构之间存在各种联系,分为三种:一对多(多对一),多对多,一对一
- 一对多:
部门与员工之间的关系:一个部门对应多个员工,一个员工对应一个部门
实现:在 ‘多的一方’ 建立外键,指向 ‘一’ 的主键
- 多对多:
学生与课程之间的关系:一个学生可以选修多门课程,一门课程也可以供多个学生选修
实现:建立一张中间表,中间表包含两个外键,分别关联两方主键
-- ------------- 多表关系 演示 ----------------
-- 多对多 ----------------
create table student(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
no varchar(10) comment '学号'
) comment '学生表';
insert into student values (null, '黛绮丝', '2000100101'),(null, '谢逊', '2000100102'),(null, '殷天正', '2000100103'),(null, '韦一笑', '2000100104');
create table course(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '课程名称'
) comment '课程表';
insert into course values (null, 'Java'), (null, 'PHP'), (null , 'MySQL') , (null, 'Hadoop');
create table student_course(
id int auto_increment comment '主键' primary key,
studentid int not null comment '学生ID',
courseid int not null comment '课程ID',
constraint fk_courseid foreign key (courseid) references course (id),
constraint fk_studentid foreign key (studentid) references student (id)
)comment '学生课程中间表';
insert into student_course values (null,1,1),(null,1,2),(null,1,3),(null,2,2),(null,2,3),(null,3,4);
- 一对一:
用户与用户详情的关系
用途:一对一关系,用于单表拆分,将一张表的基础字段放在一张表中,详情另存一表
实现:在任意一方加入外键,关联另一方的主键,并且设置外键为唯一(UNIQUE)
-- ------------------ 一对一 ---------------------------
create table tb_user(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
age int comment '年龄',
gender char(1) comment '1: 男 , 2: 女',
phone char(11) comment '手机号'
) comment '用户基本信息表';
create table tb_user_edu(
id int auto_increment primary key comment '主键ID',
degree varchar(20) comment '学历',
major varchar(50) comment '专业',
primaryschool varchar(50) comment '小学',
middleschool varchar(50) comment '中学',
university varchar(50) comment '大学',
userid int unique comment '用户ID',
constraint fk_userid foreign key (userid) references tb_user(id)
) comment '用户教育信息表';
insert into tb_user(id, name, age, gender, phone) values
(null,'黄渤',45,'1','18800001111'),
(null,'冰冰',35,'2','18800002222'),
(null,'码云',55,'1','18800008888'),
(null,'李彦宏',50,'1','18800009999');
insert into tb_user_edu(id, degree, major, primaryschool, middleschool, university, userid) values
(null,'本科','舞蹈','静安区第一小学','静安区第一中学','北京舞蹈学院',1),
(null,'硕士','表演','朝阳区第一小学','朝阳区第一中学','北京电影学院',2),
(null,'本科','英语','杭州市第一小学','杭州市第一中学','杭州师范大学',3),
(null,'本科','应用数学','阳泉第一小学','阳泉区第一中学','清华大学',4);
概述
- 指从多张表中查询数据
- 笛卡尔积:两集合AXB所有组合(在多表查询时,需要消除无效的笛卡尔积)
-- 整体笛卡尔积表
select * from emp ,dept ;
-- 去掉无效笛卡尔积后(但由于where条件存在,不能将没有部门的人也列在表中)
select * from emp,dept where emp.dept_id = dept.id;
- 多表查询分类
- 连接查询:
- 内连接:相当于查询A、B交集部分
- 外连接:
- 左外连接:查询左表所有数据,包含两张表交集部分
- 右外连接:查询右表所有数据,包含两张表交集部分
- 自连接:当前表与自身的连接查询,自连接必须使用表别名
- 子查询
- 连接查询:
连接查询-内连接
相当于查询A、B交集部分
- 隐式内连接
SELECT 字段列表 FROM 表1,表2 WHERE 条件...;
- 显式内连接
SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件...;-- inner可以省略
注意:如果 from给表起了别名 ,在 select和where等处就不能再使用原表名进行访问了
外连接
外连接查询语法:
- 左外连接
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 连接条件..;
-- 连接条件一般都是用‘=’的
相当于查询左表A中的所有数据 包含表A和表B交集部分的数据
- 右外连接
SELECT 字段列表 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 连接条件..;
相当于查询右表B中的所有数据 包含表1和表2交集部分的数据
-
- 右外改左外:只需要把表一表二位置调换,使用左外语法,即可实现右外
自连接
自连接(自己连接自己)查询语法:
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 连接条件...;
自连接查询,可以是内连接查询,也可以是外连接查询。
例:
-- 1.查询员工 及 所属领导的名字
-- 内连接,不能查询到 领导为空 的员工信息,它查的是交集
select a.name, b.name from emp a,emp b where a.managerid = b.id;
-- 2.查询所有员工 及 领导 的名字,如果员工没有领导,也要查询出来(外连接)
select a.name '员工',b.name '领导' from emp a left join emp b on a.managerid = b.id;
联合查询-union,union all
对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集
SELECT 字段列表 FROM 表A...
UNION [ALL]
SELECT 字段列表 FROM 表B...;-- 这里查询的字段列表必须相同,否则报错
UNION 是直接把查询结果合并,有重复数据依然保留
UNION ALL 是 查询结果合并 并 去重
对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致
子查询
- 概念:SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询。
SELECT * FROM t1 WHERE column1 =(SELECT column1 FROM t2);
子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT的任何一个。
-
子查询就是括号里面的那点查询
-
根据子查洵结果不同,分为:
-
标量子查询(子查询结果为单个值)
列子查询(子查询结果为一列)
行子查询(子查询结果为一行)
表子查询(子查询结果为多行多列)
-
-
根据子查询的位置,分为:WHERE之后、FROM之后、SELECT之后
标量子查询
1.查询“销售部”的所有员工信息
-- a.查询“销售部”的部门ID(dept)
select id from dept where name = '销售部';
-- b.根据销售部的ID,查询员工信息(emp)
select * from emp where dept_id = (select id from dept where name = '销售部');
列子查询
子查询返回的结果是一列
操作符 | |
---|---|
IN | 在指定的 集合范围(子查询结果列)内,分别查询对应信息 |
NOT IN | 不在指定的范围内 |
ANY | 子查询的结果有任意一个满足外层where条件 |
SOME | 与ANY一样 |
ALL | 子查询返回结果的所有值都必须满足外层where条件 |
select * from emp where salary > all (select salary from emp where dept_id = (select id from dept where name='财务部'));
普通的列查询:where dept_id in (列条件);
all和some见表格
行子查询
返回结果是一行
常用操作符:= <>(不等于) IN NOT IN
select * from emp where (salary,managerid) = (select salary,managerid from emp where name = '张无忌');
-- 上面where (salary,managerid)=其实是where salary= x and managerid=x的变体
单行查询:(salary,managerid) =(行条件)
表子查询
子查询返回的结果是多行多列,这种子查询称为表子查询
常用操作符:IN
select * from emp where (salary,managerid) in (select salary,managerid from emp where name='xx' or name='yy');
多行(表):(salary,managerid) in(表条件)
事务
事务简介
一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体,一起向系统提交或回滚操作,即这些操作要么 同时成功,要么 同时失败。
步骤:开启事务->检测异常->正常运行->提交事务
->抛出异常->回滚事务
默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务
异常模拟
-- 转账操作 (张三给李四转账1000)
-- 1. 查询张三账户余额
select * from account where name='张三';
-- 2. 将张三账户余额-1000
update account set money = money - 1000 where name='张三';
-- 输入一句不是注释,也不是代码的话当作异常
程序抛出异常...
-- 3. 将李四账户余额+1000
update account set money = money +1000 where name='李四';
程序异常:Unknown system variable 'money'
事务操作
方式一
- 设置/查看事务提交方式
SELECT @@autocommit;//1为自动提交,0为手动提交
SET @@autocommit = 0;//一般把自动提交设置为手动提交
- 提交事务
COMMIT;
- 回滚事务
ROLLBACK;
演示
-- 恢复数据
update account set money = 2000 where name='张三' or name='李四';
SELECT @@autocommit;
set @@autocommit = 0;-- 手动模式,之后恢复数据时,别忘了commit提交一下
-- 转账操作 (张三给李四转账1000)
-- 1. 查询张三账户余额
select * from account where name='张三';
-- 2. 将张三账户余额-1000
update account set money = money - 1000 where name='张三';
-- 测试异常时打开,且异常时不可提交事务,而需要回滚事务
# -- 输入一句不是注释,也不是代码的话当作异常
# 程序抛出异常...
-- 3. 将李四账户余额+1000
update account set money = money +1000 where name='李四';
-- 完成上述操作以后,提交事务,才能修改account表中的数据
commit ;
rollback ;
方式二
手动开启事务,无需设置autocommit,在BEGIN之后的语句为手动模式
- 开启事务
START TRANSACTION 或 BEGIN;
- 提交事务
COMMIT;
- 回滚事务
ROLLBACK;
事务四大特性
- 原子性(A):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性(C):事务完成时,必须使所有的数据都保持一致状态。
- 隔离性(I):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性(D):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的
并发事务问题
问题 | 描述 |
---|---|
脏读 | 一个事务读到另外一个事务还没有提交的数据 |
不可重复读 | 一个事务先后读取同一条记录,但由于其他事务在途中修改了磁盘信息,导致两次读取得到数据不同,称之为不可重复读 |
幻读 | 一个事务A按照条件查询数据时,没有对应数据行;但与此同时,与它并发的事务B进行了插入操作;导致在事务A插入数据时,发现这行数据已存在,报错,程序将会处理不可重复读的问题,消除该插入操作;使得下次查询操作还是查不到。好像出现了一个“幻影” |
解决以上问题及事务的隔离级别
事务的隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted | |||
Read committed | 可解决 | ||
Repeatable Read(MySQL默认) | 可解决 | 可解决(事务B的修改不会改变表,A的两次select结果相同,称可重复读) | |
Serializable(性能最差) | 可解决 | 可解决 | 可解决(将会阻塞事务B的修改,直到A完成操作提交之后才能执行B修改命令,此时会在B中报错) |
-- 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
-- 设置事务隔离级别(session当前会话,global所有客户端的会话窗口)
SET [SESSION \ GLOBAL] TRANSACTION ISOLATION LEVEL {read uncommitted \ Repeatable Read ...}
注意:事务隔离级别越高,数据越安全,但是性能越低。