mysql基础

本文详细介绍了SQL的基础知识,包括关系型数据库设计规则、基本的SELECT语句、运算符、排序与分页、多表查询等。深入探讨了SQL的执行原理,讲解了函数的分类、数据库的创建管理以及数据处理的增删改操作。此外,还阐述了数据类型的使用和约束的概念,为数据库管理和开发提供了全面的指南。
摘要由CSDN通过智能技术生成

1.关系型数据库设计规则
2.基本的select语句
3.运算符
4.排序与分页
5.多表查询
6.函数的分类
7.SQL底层执行原理
8.子查询
9.创建管理数据库(表)
10.数据处理之增删改
11.MySQL数据类型
12.约束

一、关系型数据库设计规则

  • 关系型数据库的典型数据结构就是数据表,这些数据表的组成都是结构化的(Structured)
  • 将数据放到表中,表再放到库中
  • 一个数据库中可以有多个表,每个表都有一个名字,用来标识自己,表名具有唯一性
  • 表具有一些特性,这些特性定义了数据在表中如何储存,类似Java和Python中“类”的设计

1.1 表、记录、字段

  • E-R模型中有3个主要概念:实体集 属性 联系集
  • 一个实体集(class)对应于数据库中的一个表(table),一个实体(instance)则对应于数据库表中的一行(row),也称为一条记录(record),一个属性(attribute)对应数据表中的一列(column),也称为一个字段(field)

1.2 表联系

  • 表与表之间的数据记录有关系(relationship)。
  • 四种:一对一关联,一对多关联,多对多关联,自我引用
1.2.1 一对一关联(one-to-one)
  • 在实际的开发中应用不多,因为一对一可以建成一张表
  • 举例:设计学生表:学号、姓名、手机号、班级、身份证、家庭住址…
    • 拆分为两个表:两个表的记录是一一对应的关系
    • 基础信息表(常用信息):学号、姓名、手机、班级
    • 档案信息表(不常用信息):学号、身份证、家庭住址…
  • 两种建表原则:
    • 外键唯一:主表的主键和从表的外键(唯一),形成主外键关系,外键唯一
    • 外键是主键:主表的主键和从表的主键,形成主外键关系
1.2.2 一对多关系(one-to-many)
  • 常见实例场景:客户表和订单表分类表和商品表部门表和员工表
  • 举例:
    • 员工表:编号、姓名、…、所属部门
    • 部门表:编号、名称、简介
  • 一对多建表原则:在从表(多方)创建一个字段,字段作为外键指向主表(一方)的主键
1.2.3 多对多关系(many-to-many)

要表示多对多关系,必须创建第三个表,该表通常称为联系表,他将多对多关系划分为两个一对多关系,将这两个表的的主键都插入到第三个表中

1.2.4 自我引用(Self referencce)

举例:

员工编号姓名主管编号
101张三NULL
102李四101
103王五102

二、基本的select语句

2.1 SQL的分类

  • DDL(数据定义语言):这些语句定义了不同的数据库、表、视图、索引等数据库对象,还可以用来创建、删除、修改数据库和表的结构
    • 主要的语句关键字包括CREATEDROPALTERRENAMETRUNCATE
    • DDL 操作一旦执行,则不能回滚。
  • DML(数据操作语言):用于添加、删除、更新和查询数据库记录,并检查数据完整性
    • 主要的语句关键字包括 INSERTSELECTDELETEUPDATE
    • DML 操作一旦执行,默认情况下是不能回滚的,但如果在执行DML 之前,执行了 SET autocommit = FALSE,则执行DML 操作就可以回滚。
  • DCL(数据控制语言):用于定义数据库、表、字段、用户的访问权限和安全级别
    • 主要的关键字包括:GRANTREVOKECOMMITROLLBACKSAVEPOINT

因为查询语句使用的非常频繁,所以很多人把查询语句单拎出来一类:DQL(数据查询语言)。
还有单独将COMMIT、ROLLBACK 取出来称为TCL(事务控制语言)

2.1.1 导入现有的数据表、表的数据

方式一:source 文件的全路径名
方式二:基于具体的图形化界面的工具导入

2.2 select 基本语句

2.2.1 select…
select 1; # 没有任何子句
select 1+2,2+3; # 没有任何子句
2.2.2 select … from …
SELECT 字段名(列名) FROM 表名
2.2.3 列的别名

注:列的别名只能在ORDER BY 中使用,不能在 WHERE中使用,因为sql的执行顺序为 FROM => WHERE => SELECT => ORDER BY

# AS可以省略
# 别名可以使用双引号("")引起来
SELECT 列名 AS 别名 FROM  表名
SELECT employees_id emp_id,last_name AS lname,department_id "dept_id",salary * 12 "annual sal"
FROM employees;
2.2.4 去除重复行

DISTINCT 关键字

# 查询部门表中有哪些部门id
SELECT deparment_id FROM employees; # 没有去重的情况
SELECT DISTINCT department_id FROM employees; # 去重后的
# 部门和工资一样得多条记录才会进行去重
SELECT DISTINCT department_id,salary FROM employees;
2.2.5 空值参与运算
  • 空值参与运算结果一定也为null
#空值:null
# null 不等同于 0 , '' , 'null'
# 查询月工资和年工资(年工资需要算上奖金率)
SELECT employee_id,salary "月工资",salary * (1 + commission_pct) * 12 "年工资"
FROM employees; # 如果commission_pct为null年工资结果就为null
# 正确写法
SELECT employee_id,salary "月工资",salary * (1 + IFNULL(commission_pct)) * 12 "年工资"
FROM employees;
2.2.6 着重号(` `)

如果表名或者字段名与关键字冲突了,必须使用着重号引起来

SELECT * FROM order; # 报错,因为order是关键字
SELECT * FROM `order`; # 正确写法
2.2.7 查询常数

表中没有这个字段,但是查询的时候需要显示在表中,并且所有记录的常数名都一样

SELECT "常数名",123,employee_id,last_name
FROM employees;

在这里插入图片描述

2.3 显示表结构

DESCCRIBEDESC

DESCRIBE employees;
DESC employees;

2.4 过滤数据

SELECT … FROM … WHERE 过滤条件

# 查询90号部门的员工信息
SELECT * FROM employees WHERE department_id=90;

三、运算符

3.1 算数运算符

+ 、 - 、* 、 /(DIV) 、 %(MOD)
注:在sql中, + 没有连接的作用,数字与字符串相加,会把字符串转换为数字

SELECT 100 + '1' FROM DUAL; # 结果为101
SELECT 100 + 'a' FROM DUAL; # 结果为100 ,'a'转换为了0
SELECT 100 + null FROM DUAL; # 结果为null,null值参与运算结构都为null;

3.2 比较运算符

3.2.1 = <=> <>(!=) > >= < <=
SELECT 1=NULL,NULL=NULL FROM DUAL; # 只要有null参与判断,结果都为null

<=> 安全等于:在没有null参与判断的情况下,作用与 = 相同,当有null参与时,只有null与null相等

SELECT 1 <=> NULL; # 0
SELECT null <=> null; # 1
3.2.2 是否为null

IS NULL IS NOT NULL ISNULL()

# 查询表中commission_pct字段为null的数据有哪些
SELECT last_name,salary,commission_pct 
FROM employees 
WHERE commission_pct IS NULL;
# 或
SELECT last_name,salary,commission_pct
FROM employees
WHERE ISNULL(commission_pct);
# 或
SELECT last_name,salary,commission_pct 
FROM employees 
WHERE commission_pct <=> NULL;

# 查询表中commission_pct字段不为null的数据有哪些
SELECT last_name,salary,commission_pct 
FROM employees 
WHERE commission_pct IS NOT NULL;
# 或
SELECT last_name,salary,commission_pct 
FROM employees 
WHERE NOT commission_pct <=> NULL;
3.2.3 最小、最大

LEAST GREATEST

SELECT LEAST('A','D','E','F'),GREATEST('A','D','E','F')
FROM DUAL; # 输出 A , F
3.2.4 区间(大于等于多少并且小于等于多少)

BETWEEN ... (下限) AND (上限) ...

#查询工资在6000到8000之间的员工
SELECT last_name,salary 
FROM employees
WHERE salary BETWEEN 6000 AND 8000;

#查询工资不在6000到8000之间的员工
SELECT last_name,salary 
FROM employees
WHERE salary NOT BETWEEN 6000 AND 8000;
# 或
SELECT last_name,salary 
FROM employees
WHERE salary < 6000 OR salary > 8000;
3.2.5 包含

IN (集合) NOT IN (集合)

# 查询部门为10,20,30的员工的信息
SELECT last_name,salary 
FROM employees
WHERE department_id IN (10,20,30);

# 查询工资不为6000,7000,8000的员工
SELECT last_name,salary
FROM employees
WHERE salary NOT IN (6000,7000,8000);
3.2.6 模糊查询

LIKE
%表示不确定个数的字符(0个或多个)
_一个_代表一个不确定的·字符
同一组%中可以写多个,如:
%a%e% 但是是有顺序限制的

# 查询last_name字段中包含'a'的员工的信息
SELECT last_name,salary
FROM employees
WHERE last_name LIKE '%a%';

# 查询last_name字段中包含'a' 并且 包含字符 'e' 的员工的信息
SELECT last_name,salary
FROM employees
WHERE last_name LIKE '%a%' AND last_name LIKE '%e%';

# 或

SELECT last_name,salary
FROM employees
WHERE last_name LIKE '%a%e%' OR last_name LIKE '%e%a%'; 

# 查询last_name中第二个字符为'a'的员工信息
SELECT last_name,salary 
FROM employees
WHERE last_name LIKE '_a%';

# 查询last_name中第一个字符为'_'的 并且 第三个字符为'a'的员工信息
SELECT last_name 
FROM employees
WHERE last_name LIKE '_\_a%';
3.2.7 REGEXP \ RLIKE : 正则表达式

REGEXP运算符用来匹配字符串,语法格式为expr REGEXP 匹配条件。如果expr满足匹配条件,返回1,如果不满足,则返回0。若expr或匹配条件任意一个为null,则结果为null。
REGEXP运算符在进行匹配时,常用的有下面几种通配符:

1.^匹配以该字符后面的字符开头的字符串
2.$匹配以该字符前面的字符结尾的字符串
3..匹配任意一个单字符
4.[......] 匹配在方括号内的任意字符。例如[a,b,c]匹配“a”或者“b”或者“c”。为了命名字符的范围,使用一个“-”,[a-z]匹配任何字母,而[0-9]匹配任何数字。
5.*匹配0个或者多个在他前面的字符。如:x*匹配任何数量的’x’字符,[0-9]*匹配任何数量的数字,而*匹配任何数量的任何字符。

SELECT 'shark' REGEXP '^sha','shark' REGEXP 'k$', 'shark' REGEXP '[a-z]'
FROM DUAL; # 输出1,1,1

3.3 逻辑运算符

逻辑非:NOT !
逻辑与:AND && 两边条件都为true 则返回true
逻辑或:OR || 两边条件有一个为true 则 返回 true
逻辑异或:XOR 两边的条件 一 true 一 false则返回true

AND的优先级是高于OR

四、排序与分页

4.1 排序数据

4.1.1 排序规则
  • 使用ORDER BY子句进行排序。不指明排序方法,默认情况下是按照ASC升序进行排序
    • ASC(accend) 升序
    • DESC(descend) 降序
  • 可以适应列的别名进行排序
4.1.2 单列排序
# 员工工资从高到低进行排序
SELECT last_name,salary 
FROM employees
ORDER BY salary DESC;
4.2.2 多列排序
  • 在对多列进行排序的时候,首先排序的第一列必须有相同的值,才会对第二列进行排序。如果第一列中所有的值都是唯一的,将不在对第二列进行排序。
# 显示员工信息表,按照department_id降序排序,salary的升序排序
SELECT last_name,salary,department_id
FROM employees
ORDER BY department_id DESC,salary;

4.2 分页

分页公式: 偏移量 = ( 当前页 - 1 ) * 一页的数据量

4.2.1 实现

LIMIT

LIMIT [数据偏移量,]行数
# 查找第一页数据,每页20条数据
SELECT employee_id,last_name
FROM employees
LIMIT 0,20

# 查找第二页数据,每页20条数据
SELECT employee_id,last_name
FROM employees
LIMIT 20,20

# 查找第三页数据,每页20条数据
SELECT employee_id,last_name
FROM employees
LIMIT 20 OFFSET 40; # OFFSET 是mysql8的新特性,代表偏移量 与LIMIT 40,20 相同

五、多表查询

  • 多表查询需要有连接条件,若没有连接条件,会造成笛卡尔积错误。
  • 如果查询语句中出现了多个表中都存在的字段,必须指明次字段所在的表表名.字段名
  • 建议:从sql优化的角度讲,在多表查询时,建议每个字段前都指明其所在的表
  • 如果有n个表实现多表查询,则需要至少 n - 1个连接条件
employees;  # 员工表
departments;  # 员工部门表
locations;  # 员工位置表
员工部门表(主表)=> 员工表(从表)department_id
员工位置表(主表)=> 员工部门表(从表)location_id

5.1 等值连接 vs 非等值连接

5.1.1 等值连接
# 查询所有员工的部门名称
SELECT emp.department_id,dept.部门名称字段  # 不想翻了
FROM employees AS emp,departments AS dept
WHERE emp.department_id = dept.department_id;
5.1.2 非等值连接
# 查询每个员工的工资是属于哪个等级
SELECT emp.last_name,emp.salary,jgrad.grade_level
FROM employees AS emp,job_grades as jgrad
WHERE emp.salary BETWEEN jgrad.lowest_sal AND jgrad.highest_sal;

5.2 自连接 vs 非自连接

5.2.1 自连接
  • 物理上是同一张表
  • 逻辑上是两张表
# 查询员工id。姓名极其管理者的id和姓名
SELECT emp.employee_id,emp.last_name,mgr.employee_id,mgr.last_name
FROM employees AS emp,employees AS mgr
WHERE emp.employee_id = mgr.manager_id;
5.2.2 非自连接
  • 只要不是自我引用的多表查询方式,都属于非自连接

5.3 内连接 vs 外连接

  • 内连接:合并具有同一列的两个以上的表的行,结果集中不包含一个表与另一个表不匹配的行
  • 外连接:两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行,这种连接称为左(或右)连接。没有匹配的行时,结果表中相应的列为null
  • 如果是左(右)外连接,则连接条件中左(右)边的表称为主表,右(左)边的表称为从表
5.3.1 内连接

[INNER] JOIN...ON..

# 内连接
#两个表内连接
SELECT emp.last_name,dept.department_name
FROM employees AS emp JOIN departments AS dept
ON emp.department_id = dept.department_id;
# 三个或多个表内连接
SELECT emp.last_name,dept.department_name,l.city
FROM employees AS emp JOIN departments AS dept
ON emp.department_id = dept.department_id
JOIN locations AS l
ON dept.location_id = l.location_id;
5.3.2 左外连接

LEFT [OUTER] JOIN... ON...

# 查询所有员工的 lasr_name,department_name
SELECT emp.last_name,dept.department_name
FROM employees AS emp LEFT JOIN departments AS dept
ON emp.department_id = dept.department_id;
5.3.2 右外连接

RIGHT [OUTER] JOIN... ON...

SELECT emp.last_name,dept.department_name
FROM employees AS emp RIGHT JOIN departments AS dept
ON emp.department_id = dept.department_id;
5.3.3 满(全)外连接(MySQL不支持)
SELECT emp.last_name,dept.department_name
FROM employees AS emp FULL JOIN departments AS dept
ON emp.department_id = dept.department_id;
5.3.4 UNION的使用

作用: 合并查询结果
利用UNION关键字,可以给出多条SELECT语句,并将他们的结果组成单个结果集合并时,两个表对应的列数和数据类型必须相同,并且相互对应。各个SELECT语句之间使用UNIONUNION ALL 关键字分割
语法格式:

SELECT column,... FROM table1
UNION [ALL]
SELECT column,... FROM table2
  • UNION 操作符:UNION操作符返回两个查询的结果集的并集,去除重复记录
  • UNION ALL擦作符:UNION ALL操作符返回两个查询的结果集的并集。对于结果集重复的部分,不去重。

注意:执行UNION ALL语句是所需要的资源比UNION少,如果明确知道合并后的数据不存在重复数据,或者不需要去除重复的数据,则尽量使用UNION ALL语句,以提高数据查询效率

5.4 自然连接 vs 非自然连接(SQL99新特性)

  • 自然连接NATURAL JOIN
    自然连接相当于SQL92中的等值连接,它会帮助你自动查询两张接连表中所有相同的字段,然后进行等值连接
SELECT emp.employee_id,emp.last_name,dept.department_name
FROM employees AS emp JOIN departments AS dept
ON emp.department_id = dept.department_id
AND emp.manager_id = dept.manager_id;

#  相当于

SELECT emp.employee_id,emp.last_name,dept.department_name
FROM employees AS emp NATURAL JOIN departments AS dept;
  • USING
    USING指定数据表的同名字段进行等值连接。但是只能配合JOIN一起使用
SELECT emp.employee_id,emp.last_name,dept.department_name
FROM employees AS emp JOIN departments AS dept
ON emp.department_id = dept.department_id;

# 相当于
SELECT emp.employee_id,emp.last_name,dept.department_name
FROM employees AS emp JOIN departments AS dept
USING (department_id);

5.5 7种JOIN的实现

在这里插入图片描述

A => 员工表 employees
B => 部门表 departments
  • 中图:内连接
SELECT emp.last_name,dept.department_name
FROM employees AS emp JOIN departments AS dept
ON emp.department_id = dept.department_id;
  • 左上图:左外连接
SELECT emp.last_name,dept.department_name
FROM employees AS emp LEFT JOIN departments AS dept
ON emp.department_id = dept.department_id;
  • 右上图:右外连接
SELECT emp.last_name,dept.department_name
FROM employees AS emp RIGHT JOIN departments AS dept
ON emp.department_id = dept.department_id;
  • 左中图:
SELECT emp.last_name,dept.department_name
FROM employees AS emp LEFT JOIN departments AS dept
ON emp.department_id = dept.department_id
WHERE dept.department_id IS NULL;
  • 右中图:
SELECT emp.last_name,dept.department_name
FROM employees AS emp RIGHT JOIN departments AS dept
ON emp.department_id = dept.department_id
WHERE emp.department_id IS NULL;
  • 左下图:满外连接
# 方式一:左上图 UNION ALL 右中图
SELECT emp.last_name,dept.department_name
FROM employees AS emp LEFT JOIN departments AS dept
ON emp.department_id = dept.department_id
UNION ALL
SELECT emp.last_name,dept.department_name
FROM employees AS emp RIGHT JOIN departments AS dept
ON emp.department_id = dept.department_id
WHERE emp.department_id IS NULL;

# 方式二:左中图 UNION ALL 右上图
SELECT emp.last_name,dept.department_name
FROM employees AS emp LEFT JOIN departments AS dept
ON emp.department_id = dept.department_id
WHERE dept.department_id IS NULL
UNION ALL
SELECT emp.last_name,dept.department_name
FROM employees AS emp RIGHT JOIN departments AS dept
ON emp.department_id = dept.department_id;
  • 右下图:
# 左中图 UNION ALL 右中图
SELECT emp.last_name,dept.department_name
FROM employees AS emp LEFT JOIN departments AS dept
ON emp.department_id = dept.department_id
WHERE dept.department_id IS NULL
UNION ALL
SELECT emp.last_name,dept.department_name
FROM employees AS emp RIGHT JOIN departments AS dept
ON emp.department_id = dept.department_id
WHERE emp.department_id IS NULL;

注意

我们要控制连表的数量,多表连接就相当于嵌套for循环一样,非常消耗资源,会让sql的查询性能下降的很严重,因此不要连接不必要的表。在许多DBMS中,也都会有最大连表的限制
【强制】超过三个表禁止join。需要join的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引
说明:即使双表查询也要注意表索引、SQL性能。

六、函数的分类

6.1 单行函数(太多了,百度吧)

获取时间戳:UNIX_TIMESTAMP()

6.2 流程控制函数

函数用法
IF(value,value1,value2)如果value的值为true,则返回value1,否则返回value2
IFNULL(value1,value2)如果value1不为null返回value1,否则返回value2
CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 … [ELSE 结果3] END相当于 if…else if … else…
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值2 THEN 值2 … [ELSE 值n] END相当于 switch … case…

6.3 聚合函数(常见的5个聚合函数)

6.3.1 AVG (平均数) / SUM(总和)
SELECT AVG(salary),SUM(salary) 
FROM employees;
6.3.2 MAX(最大) / MIN(最小)

适用于数值类型,字符串类型,日期时间类型的字段

SELECT MAX(salary),MIN(salary)
FROM employees;
6.3.3 COUNT(数量)

作用: 计算指定字段在查询结果中出现的个数
注意:计算指定字段出现的个数时,是不计算空值的

  • 公式:AVG = SUM / COUNT

6.4 GROUP BY(分组查询)

SELECT中出现的非聚合函数的字段必须声明在GROUP BY中。反之,GROUP BY中声明的字段可以不出现在SELECT中

# 查询各个部门的平均工资
SELECT department_id,AVG(salary),SUM(salary)
FROM employees
GROUP BY department_id;

6.5 HAVING的使用(过滤数据)

  • 如果过滤条件中使用了聚合函数,则必须使用HAVING代替WHERE。否则报错。
  • 如果有GROUP BYHAVING必须声明在ORDER BY 的后边。
# 查询每个部门的最高工资并且大于10000
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) > 10000
ORDER BY AVG(salary) ASC;

# 查询部门编号为10,20,30,40的部门的最高工资并且大于10000
# 推荐
SELECT department_id,MAX(salary)
FROM employees
WHERE department_id IN (10,20,30,40)
GROUP BY department_id
HAVING MAX(salary) > 10000; 
# 或
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) > 10000 AND department_id IN (10,20,30,40);

七、SQL底层执行原理

7.1 SELECT语句的完整结构

7.1.1 SQL92 语法:
SELECT ...,...,... (存在聚合函数)
FROM ...,...,...
WHERE 多表的连接条件 AND 不包含聚合函数的过滤条件
GROUP BY ...,...
HAVING 包含聚合函数的过滤条件
ORDER BY ...,...ASC / DESCLIMIT ...
7.1.2 SQL99 语法:
SELECT ...,...,... (存在聚合函数)
FROM ... (LEFT / RIGHT) JOIN ... ON 多表的连接条件
(LEFT / RIGHT) JOIN ... ON 多表的连接条件
WHERE 不包含聚合函数的过滤条件
GROUP BY ...,...
HAVING 包含聚合函数的过滤条件
ORDER BY ...,...ASC / DESCLIMIT ...

7.2 SQL语句的执行过程

其实在每一个步骤都会产生一个虚拟表
FROM => ON => (LEFT / RIGHT) JOIN => WHERE => GROUP BY => HAVING => SELECT => DISTINCT => GROUP BY => LIMIT

八、子查询

# 查询谁的工资比Abel高
SELECT last_name,salary
FROM employees
WHERE salary > (SELECT salary
				FROM employees
				WHERE last_name = 'Abel');
8.1.1 称谓的规范:外查询(或主查询),内查询(或子查询)
  • 子查询在主查询之前一次执行完成
  • 子查询的结果被主查询使用
  • 注意事项:
    • 子查询要包含在括号内
    • 将子查询放在比较条件的右侧
    • 单行操作符对应单行子查询,多行操作符对应多行子查询

8.2 子查询分类

角度1:按子查询返回的结果行数
分为:

  • 单行子查询
  • 多行子查询

角度2:按内查询是否被执行多次
分为:

  • 相关子查询
  • 不相关子查询

8.3 单行子查询

单行子查询比较操作符:= > >= < <= != <>

# 查询与 141 号员工的 manager_id,department_id相同的其他员工的employee_id,manager_id,department_id
SELECT employee_id,manager_id,department_id
FROM employees
WHERE manager_id = (SELECT manager_id 
					FROM employees 
					WHERE employee_id = 141)
AND department_id = (SELECT department_id 
					FROM employees 
					WHERE employee_id = 141)
AND employee_id != 141;
8.3.1 HAVING中的子查询
# 查询最低工资大于50号部门最低工资的部门id和其最低工资
SELECT department_id,MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary) > (SELECT MIN(salary) 
						FROM employees
						WHERE department_id = 50);
8.3.1 CASE中的子查询
# 显示员工的employee_id,last_name和location,其中,若员工department_id与location_id为1800的department_id相同,则location为‘Canada’,其余则为‘USA’
SELECT employee_id,last_name,(CASE department_id
	WHEN (SELECT department_id FROM departments WHERE location_id = 1800) THEN
		"Canada"
	ELSE
		"USA"
	END) "location"
FROM employees;

8.4 多行子查询

多行子查询比较操作符:

操作符含义
IN等于列表中的任意一个
ANY需要和单行比较操作符符一起使用,和子查询返回的某一个值比较
ALL需要和单行比较操作符符一起使用,和子查询返回的所有值比较
SOME实际上是ANY的别名,作用相同,一般常用ANY
# 查询平均工资最低的部门
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (SELECT MIN(avg_salary)
					  FROM (SELECT AVG(salary) AS avg_salary 
								FROM employees 
								GROUP BY department_id) AS t_dept_avg);

# 或
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL (SELECT AVG(salary) AS avg_salary 
							FROM employees 
							GROUP BY department_id);

8.5 相关子查询

8.5.1相关子查询执行流程

如果子查询的执行依赖于外部查询,通常情况下都是因为子查询的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询称为关联子查询
相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询
在这里插入图片描述
说明:子查询中使用主查询中的列

8.5.2代码示例

WHERE中使用相关子查询

# 查询员工中工资大于本部门平均工资的员工的last_name,salary,和其department_id
SELECT last_name,salary,department_id
FROM employees emp1
WHERE salary > (
	SELECT AVG(salary)
	FROM employees emp2
	WHERE department_id = emp1.department_id
);

综合习题:

#1.查询和Zlotkey相同部门的员工姓名和工资
SELECT last_name,salary
FROM employees
WHERE department_id = (
	SELECT department_id
	FROM employees
	WHERE last_name="Zlotkey"
);

#2.查询工资比公司平均工资高的员工的员工号,姓名和工资
SELECT employee_id,last_name,salary
FROM employees
WHERE salary > (
	SELECT AVG(salary)
	FROM employees
);

#3.选择工资大于所有JOB_ID = 'SA_MAN'的员工的工资的员工的last_name, job_id, salary
SELECT last_name,job_id,salary
FROM employees
WHERE salary > ALL (
	SELECT salary
	FROM employees
	WHERE job_id = 'SA_MAN'
);

#4.查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名
SELECT employee_id,last_name
FROM employees
WHERE department_id = ANY (
	SELECT DISTINCT department_id
	FROM employees
	WHERE last_name LIKE '%u%'
);

#5.查询在部门的location_id为1700的部门工作的员工的员工号
SELECT employee_id
FROM employees
WHERE department_id IN (
	SELECT department_id 
	FROM departments
	WHERE location_id = 1700
);

#6.查询管理者是King的员工姓名和工资
SELECT last_name,salary
FROM employees
WHERE manager_id IN (
	SELECT employee_id
	FROM employees
	WHERE last_name = 'King'
);

#7.查询工资最低的员工信息: last_name, salary
SELECT last_name,salary FROM employees WHERE salary = ( SELECT MIN(salary) FROM employees );

#8.查询平均工资最低的部门信息
SELECT *
FROM departments
WHERE department_id = (
	SELECT department_id
	FROM employees
	GROUP BY department_id
	HAVING AVG(salary) <= ALL (
			SELECT AVG(salary)
			FROM employees
			GROUP BY department_id
	)
);

#9.查询平均工资最低的部门信息和该部门的平均工资(相关子查询)
SELECT d.*,(SELECT AVG(salary) FROM employees WHERE department_id = d.department_id) avg_sal
FROM departments d
WHERE department_id = (
	SELECT department_id
	FROM employees
	GROUP BY department_id
	HAVING AVG(salary) <= ALL (
			SELECT AVG(salary)
			FROM employees
			GROUP BY department_id
	)
);

#10.查询平均工资最高的 job 信息
SELECT *
FROM jobs
WHERE job_id = (
	SELECT job_id
	FROM employees
	GROUP BY job_id
	HAVING AVG(salary) = (
		SELECT MAX(max_salary)
		FROM (
			SELECT AVG(salary) max_salary
			FROM employees
			GROUP BY job_id
		) t_salary
	)
);


#11.查询平均工资高于公司平均工资的部门有哪些?
SELECT department_id,department_name
FROM departments
WHERE department_id IN (
	SELECT department_id 
	FROM employees
	GROUP BY department_id
	HAVING AVG(salary) > (
		SELECT AVG(salary)
		FROM employees
	)
)

#12.查询出公司中所有 manager 的详细信息
SELECT *
FROM employees
WHERE employee_id IN (
	SELECT manager_id
	FROM employees
	
);

#13.各个部门中 最高工资中最低的那个部门的 最低工资是多少?
SELECT MIN(salary)
FROM employees
WHERE department_id = (
	SELECT department_id
	FROM employees
	GROUP BY department_id
	HAVING MAX(salary) = (
		SELECT MIN(max_salary)
		FROM (
			SELECT MAX(salary) max_salary
			FROM employees
			GROUP BY department_id
		) t_salary_max
	)
) 

#14.查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary
 SELECT last_name, department_id, email, salary
 FROM employees
 WHERE employee_id = (
	SELECT manager_id
	FROM departments
	WHERE department_id = (
		SELECT department_id
		FROM employees
		GROUP BY department_id
		HAVING AVG(salary) = (
			SELECT MAX(max_salary)
			FROM (
				SELECT AVG(salary) max_salary
				FROM employees
				GROUP BY department_id
			) t_max_salary
		)
	)
 );

#15. 查询部门的部门号,其中不包括job_id是"ST_CLERK"的部门号
SELECT department_id 
FROM departments d 
WHERE department_id NOT IN ( 
	SELECT DISTINCT department_id 
	FROM employees 
	WHERE job_id = 'ST_CLERK' 
);

# 选择所有没有管理者的员工的last_name
SELECT last_name 
FROM employees
WHERE manager_id IS NULL;

#17.查询员工号、姓名、雇用时间、工资,其中员工的管理者为 'De Haan'
SELECT employee_id,last_name,hire_date,salary
FROM employees
WHERE manager_id = (
	SELECT employee_id
	FROM employees
	WHERE last_name = 'De Haan'
);

#18.查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资(相关子查询)
SELECT employee_id,last_name,salary
FROM employees emp1
WHERE salary > (
	SELECT AVG(salary)
	FROM employees emp2
	WHERE emp1.department_id = emp2.department_id
);

#19.查询每个部门下的部门人数大于 5 的部门名称(相关子查询)
SELECT department_name
FROM departments d
WHERE 5 < (
	SELECT COUNT(*)
	FROM employees e
	WHERE d.department_id = e.department_id
);

#20.查询每个国家下的部门个数大于 2 的国家编号(相关子查询)
SELECT country_id 
FROM locations l 
WHERE 2 < ( 
	SELECT COUNT(*) 
	FROM departments d 
	WHERE l.`location_id` = d.`location_id` 
);

九、创建管理数据库(表)

9.1 创建数据库

  • 方式1:创建数据库
CREATE DATABASE 数据库名
  • 方式2:创建数据库并指定字符集
CREATE DATABASE 数据库名 CHARACTER SET 字符集;
  • 方式3:判断是否存在数据库,不存在则创建(推荐)
CREATE DATABASE IF NOT EXISTS 数据库名
# 查看创建数据库详情(默认设置的数据库类型,字符集...)
SHOW CREAETE DATABASE 数据库名

9.2 管理数据库

  • 查看当前连接中的数据库有哪些
SHOW DATABASES;
  • 切换数据库
use 数据库名
  • 查看当前数据库中保存的数据表
SHOW TABLES;
  • 查看当前正在使用的数据库
SELECT DATABASE() [FROM DUAL];
  • 查看指定数据库下保存的数据表
SHOW TABLES FROM 数据库名;

9.3 修改数据库

注意:数据库的表明是无法修改的

  • 更改数据库字符集
ALTER DATABASE 数据库名 CHARACTER SET '字符集'

9.4 删除数据库

  • 方式1:
DROP DATABASE 数据库名;
  • 方式2:(推荐)
DROP DATABASE IF EXISTS 数据库名;

9.5 MySQL 的数据类型

类型类型举例
整数类型TINYINT、SMALLINT、MEDIUMINT、INT(或INTEGER)、BIGINT
浮点类型FLOAT、DOUBLE
定点数类型DECIMAL
位类型BIT
日期时间类型YEAR、TIME、DATE、DATETIME、TIMESTAMP
文本字符串类型CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT
枚举类型ENUM
集合类型SET
二进制字符串类型BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB
JSON类型JSON对象、JSON数组
空间数据类型单值:GEOMETRY、POINT、LINESTRING、POLYGON;集合:MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、 GEOMETRYCOLLECTION

其中,常用的几类介绍如下:

数据类型描述
INT从 -231 到 231-1 的整型数据。存储大小为 4个字节
CHAR(size)定长字符数据。若未指定,默认为1个字符,最大长度255
VARCHAR(size)可变长字符数据,根据字符串实际长度保存,必须指定长度
FLOAT(M,D)单精度,占用4个字节,M=整数位+小数位,D=小数位。 D<=M<=255,0<=D<=30,默认M+D<=6
DOUBLE(M,D)双精度,占用8个字节,D<=M<=255,0<=D<=30,默认M+D<=15
DECIMAL(M,D)高精度小数,占用M+2个字节,D<=M<=65,0<=D<=30,最大取值范围与DOUBLE相同。
DATE日期型数据,格式’YYYY-MM-DD’
BLOB二进制形式的长文本数据,最大可达4G
TEXT长文本数据,最大可达4G

9.6 数据表操作

9.6.1 创建数据表(需要用户具备创建表的权限)

方式一:

 CREATE TABLE IF NOT EXISTS 表名 (
 	字段名1 数据类型 [约束条件] [默认值],
 	字段名2 数据类型 [约束条件] [默认值],
 	字段名3 数据类型 [约束条件] [默认值],
 	......
 	[表约束条件]
);

方式二:基于现有的表

CREATE TABLE 表名
AS
SELECT employee_id,last_name,salary
FROM employees;
9.6.2修改表 --> ALTER TABLE
  • 添加一个字段
    ALTER TABLE 表名
    ADD 字段名 数据类型 [约束条件] [默认值]
    [FIRST | AFTER] 字段名
# 默认添加到最后
ALTER TABLE myemp1 
ADD emp_address2 VARCHAR(40) NOT NULL
# 添加到某个字段之后
ALTER TABLE myemp1 
ADD emp_address2 VARCHAR(40) NOT NULL
AFTER id;
# 添加到第一个
ALTER TABLE myemp1 
ADD emp_address3 VARCHAR(40) NOT NULL
FIRST;
  • 修改一个字段:数据类型,长度,默认值
    ALTER TABLE 表名
    MODIFY 字段名 数据类型 [约束条件] [默认值]
ALTER TABLE myemp1
MODIFY emp_address2 VARCHAR(40);
  • 重命名一个字段
    ALTER TABLE 表名
    CHANGE 旧字段名 新字段名 数据类型 [约束条件] [默认值]
ALTER TABLE myemp1
CHANGE emp_address2 emp_address4 VARCHAR(49);
  • 删除一个字段
    ALTER TABLE 表名
    DROP COLUMN 字段名
ALTER TABLE myemp1
DROP COLUMN emp_address4;
9.6.3重命名表
  • 方式一:
    RENAME TABLE 表名
    TO 新表名
RENAME TABLE myemp1
TO myemp11;
  • 方式二:
    ALTER TABLE 表名
    RENAME TO 新表名
ALTER TABLE myemp11
RENAME TO myemp1;
9.6.4删除表

DROP TABLE 表名

9.6.5清空表

TRUNCATE TABLE 表名
TRUNCATEDELETE 对比:

  • 相同点:都可以实现删除表中的数据,同时保留表结构
  • 不同点:
    • TRUNCATE 执行完后数据不能回滚
    • DELETE 执行完后数据可以回滚

9.7 DCL中的 COMMIT 和 ROLLBACK

  • COMMIT:提交数据,一旦执行COMMIT,则数据就被永久的保存在了数据库中,意味着数据不可以回滚。
  • ROLLBACK: 回滚数据,一旦执行ROLLBACK,则可以实现数据的回滚,回滚到最近一次的COMMIT之后。

对比 TRUNCATEDELETE:
DELETE

COMMIT;
SELECT * from emp3;
SET autocommit = FALSE;
DELETE FROM emp3;
SELECT * from emp3;
ROLLBACK;
SELECT * FROM emp3; # 数据回来了

TRUNCATE

COMMIT;
SELECT * from emp3;
SET autocommit = FALSE;
TRUNCATE TABLE emp3;
SELECT * from emp3;
ROLLBACK;
SELECT * FROM emp3; # 数据为空

十、数据处理之增删改

10.1 插入数据

  • 方式一:VALUES的方式添加

① 没有指明添加的字段,必须按照声明时候的字段顺序去依次添加,为空的字段用null填充

INSERT INTO emp1 
VALUES (1,"zhangsan","2000-3-16",3400),
(2,"lisi","2000-3-17",3500);

② 指明要添加的字段,可以不添加表中已经声明的字段,默认null填充

INSERT INTO emp1(id,salary,user_name,hire_date) 
VALUES (3,5000,'wangwu','2000-4-16');
  • 方式二:将查询结果插入到表中
    注意:emp1 表中要添加的字段长度不能低于employess表
INSERT INTO emp1 (id,salary,user_name,hire_date)
SELECT employee_id,salary,last_name,hire_date
FROM employees
WHERE department_id IN (60,70);

10.2 更新数据

UPDATE 表名 SET ... WHERE ...

UPDATE emp1
SET hire_date = CURDATE()
WHERE user_name = 'wangwu';

10.3 删除数据

DELETE FROM 表名 WHERE ...

DELETE FROM emp1
WHERE id = 3;

10.4 计算列

在MySQL 8.0 中,CREATE TABLE 和 ALTER TABLE 都支持添加计算列。
例:声明字段a、b、c,其中字段c为计算列,用来计算 a+b的和

CREATE TABLE test1 (
	a INT,
	b INT,
	c INT GENERATED ALWAYS AS (a+b) VIRTUAL
);

INSERT INTO test1 (a,b)
VALUES (10,20);

SELECT * FROM test1;
UPDATE test1
SET a = 100;

十一、MySQL 数据类型

类型类型举例
整数类型TINYINT、SMALLINT、MEDIUMINT、INT(或INTEGER)、BIGINT
浮点类型FLOAT、DOUBLE
定点数类型DECIMAL
位类型BIT
日期时间类型YEAR、TIME、DATE、DATETIME、TIMESTAMP
文本字符串类型CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT
枚举类型ENUM
集合类型SET
二进制字符串类型BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB
JSON类型JSON对象、JSON数组
空间数据类型单值:GEOMETRY、POINT、LINESTRING、POLYGON;集合:MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、 GEOMETRYCOLLECTION

常见数据类型属性,如下:

MySQL关键字含义
NULL数据列可包含NULL值
NOT NULL数据列不允许包含NULL值
DEFAULT默认值
PRIMARY KEY主键
AUTO_INCREMENT自动递增,适用于整数类型
UNSIGNED无符号
CHARACTER SET name指定一个字符集

11.1 整数类型

整数类型一共有5种,包括TINYINT SMALLINT MEDIUMINT INT(INTEGER) BIGINT
区别如下:

整数类型字节有符号数取值范围无符号数取值范围
TINYINT1-128 ~ 1270 ~ 255
SMALLINT2-32768 ~ 327670 ~ 65535
MEDIUMINT3-8388608 ~ 83886070~16777215
INT、INTEGER4-2147483648 ~ 21474836470 ~4294967295
BIGINT8-9223372036854775808 ~ 92233720368547758070 ~ 18446744073709551615

11.2 定点数类型(DECIMAL)

数据类型字节含义
DECIMAL(M,D)M + 2字节有效范围由M和D决定
  • DECIMAL(M,D) 的最大取值范围和DOUBLE一样
  • 定点数在MySQL内部是以字符串的形式进行存储

11.3 日期与时间类型

  • YEAR 类型通常用来表示年
  • DATE 类型通常用来表示年、月、日
  • TIME 类型通常用来表示时、分、秒
  • DATETIME 类型通常用来表示年、月、日、时、分、秒
  • TIMESTAMP 类型通常用来表示带时区的年、月、日、时、分、秒
类型名称字节日期格式最小值最大值
YEAR1YYYY或YY19012155
TIME时间3HH:MM:SS-838:59:59838:59:59
DATE日期3YY-MM-DD1000-01-019999-12-03
DATETIME日期时间8YYYY-MM-DD HH:MM:SS1000-01-01 00:00:009999-12-03 23:59:59
TIMESTAMP日期时间4YYYY-MM-DD HH:MM:SS1970-01-01 00:00:00 UTC2038-01-19 03:14:07 UTC
11.3.1 YEAR类型

在MySQL中,YEAR有一下几种存储格式:

  • 以4位字符串或数字格式表示YEAR类型,其格式为YYYY,最小值为1901,最大值为2155
  • 以2位字符串格式表示YEAR类型,最小值为00,最大值为99。
    • 当取值为 01 到 69 时,表示 2001 到 2069
    • 当取值为 70 到 99 时,表示 1970 到 1999
    • 当取值整数的 00 或 0 添加的话,是 0000 年
    • 当取值是日期/字符串的’0’添加的话,是2000年
11.3.2 DATE 类型
  • YYYY-MM-DD格式或者YYYYMMDD格式表示的字符日期,其最小取值为1000-01-01,最大取值为9999-12-03。YYYYMMDD会被转换为YYYY-MM-DD。
  • YY-MM-DD格式或者YYMMDD格式表示的字符串日期中的两位年份转换规则与YEAR类型相同。
  • 使用CURRENT_DATE()或者NOW()函数,会插入当前系统的日期
11.3.3 TIME 类型

在MySQL中,向TIME类型的字段插入数据时,也可以使用几种不同的格式。

  • 可以使用带有冒号的字符串,比如 'D HH:MM:SS' 'HH:MM:SS' 'HH:MM' 'D HH:MM' 'D HH''SS'格式。其中 D 表示天,其最小值为0,最大值为34。如果使用带有格式的字符串插入TIME类型的字段时,D会被转换为小时,计算格式为D*24+HH。当使用带有冒号且不带D的字符串表示时间时,表示当天的事件,比如12:10表示12:10:00,而不是00:12:10
  • 可以使用不带有冒号的字符串或者数字,格式为'HHMMSS'或者HHMMSS,如果插入一个不合法的字符串或者数字,在存储数据时,会自动转换为 00:00:00。比如12:10,会将最右边的两位解析成秒,表示00:12:10,而不是12:10:00
11.3.4 DATETIME 类型
  • 存储格式为'YYYY-MM-DD HH:MM:SS' 'YY-MM-DD HH:MM:SS' 'YYYYMMDDHHMMSS' 'YYMMDDHHMMSS',也可以是数值格式YYYYMMDDHHMMSS YYMMDDHHMMSS
11.3.5 TIMESTAMP 类型
  • 存储数据的时候需要对当前时间所在的时区进行转换,查询数据的啥时候再讲时间转换为当前的时区。因此,使用TIMESTAMP存储的同一个时间值,在不同的时区查询时会显示不同的时间

修改当前时区:
中国属于东八区
SET time_zone = '+8:00'

11.4 文本字符串类型

文本类型字符串整体上分为CHAR VARCHAR TINYTEXT TEXT MEDIUMTEXT LONGTEXT ENUM SET等类型

文本字符串类型值的长度长度范围占用的存储空间
CHAR(M)M0<=M<=255M个字节
VARCHAR(M)M0<=M<=65535M+1个字节
TINYTEXTL0<=L<=255L+2个字节
TEXTL0<=L<=65535L+2个字节
MEDIUMTEXTL0<=L<=16777215L+3个字节
LONGTEXTL0<=L<=4294967295L+4个字节
ENUML1<=L<=655351或2个字节
SETL0<=L<=641,2,3,4或8个字节
11.4.1 ENUM 类型

声明的时候:

CREATE TABLE test(
	s ENUM('春','夏','秋','冬','unknow')
);

添加的时候:

INSERT INTO test(s) VALUES ('春');
#或
# 下标从1开始
INSERT INTO test(s) VALUES (1);

每条数据添加的时候只能在声明枚举类型字段中选一个,不能写多个。

11.4.2 SET 类型

与ENUM类型相似,不通点在于SET 可以添加多个

11.5 二进制字符串类型

11.5.1 BINARY和VARBINARY

类似于 CHAR 和 VARCHAR ,不同点在存储的是二进制字符串

十二、约束

12.1 约束的分类

  • 角度1:约束的字段的个数:
    单列约束 vs 多列约束
  • 角度2:约束的作用范围
    • 列级约束:将此约束声明在对应字段后边
    • 表级约束:将表中所有字段都声明完,在所有字段的后边声明的约束
  • 角度3:约束的作用(或功能)
    • NOT NULL 非空约束
    • UNIQUE 唯一性约束
    • PRIMARY KEY 主键约束
    • FOREIGN KEY 外键约束
    • CHECK 检查约束
    • DEFAULT 默认值约束
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值