一、数据库概述
为什么要使用数据库?
持久化:将数据保存到可掉电式存储设备中以供后续使用。大多数情况下,数据持久化意味着将内存中的数据保存到硬盘中加以固化,而持久化的实现过程大多通过各种关系数据库来完成。
持久化的作用:将内存中的数据存储在关系型数据库中。
数据库与数据库管理系统
1、数据库的相关概念
**DB(Data Base):**数据库,即存储数据的仓库,本质是一个文件系统。
**DBMS(Data Base Management System):**数据库管理系统,一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制,用户通过DBMS访问数据库中的表内内容。
**SQL(Structured Query Language):**结构化查询语言,专用于与数据库通信的语言。
2、DB与DBMS的关系
DBMS可以管理多个DB,一般开发人员会针对每一个应用创建一个数据库。
二、关系型数据库(RDB)设计规则
关系型数据库的典型数据结构就是数据表,这些数据表的组成都是结构化的。
将数据放到表中,再将表放到数据库中。
一个数据库中可以有多个表,每个表都有一个名字,用来标识自己,表明具有唯一性。
**E-R(实体-联系)**模型中三个主要概念:实体集、属性、联系集。
一个实体集(class)对应于数据库中的一个表(table),一个实体(instance)对应于数据库表中的一行(row),也称为一条记录(record)。
一个属性(attribute)对应于数据库表中的一列(column),也称为一个字段(field)。
表的关联关系:
表与表之间的数据记录有联系。现实世界中的各种实体以及实体之间的各种联系均用关系模型来表示。
有以下四种:
一对一、一对多、多对多、自我引用。
SQL分类:
SQL语言在功能上主要分为以下三类:
1、DDL(Data Definition Language):数据库定义语言
用于定义不同的数据库、标示图、索引等数据库对象,还可以用来创建、删除、修改、数据库和数据表的结构。
2、DML(Data Manipulation Language):数据库操作语言
用于添加、删除、更新和查询数据库记录,并检查数据完整性。
3、DCL(Data Contorl Language):数据库控制语言
用于定义数据库、表、字段、用户的访问权限和安全级别。
导入现有数据表的方法:
1、source + 文件全路径
2、使用可视化工具直接导入(Navicat)
基础篇数据库连接:
链接: https://pan.baidu.com/s/1Rk4Swoo8clDkYpo6op774g?pwd=1024 提取码: 1024
三、基本的SELECT语句
SELECT查询:
SELECT 字段名 FROM 表名;
SELECT * FROM countries;
列的别名:
SELECT 字段名1 AS 别名, 字段名2 AS 别名 FROM 表名; (AS可省略)
SELECT employee_id emp_id, email e
FROM employees;
在要查询的字段名后空一格再输入别名,输出的结果集中就会显示新的字段名。
也可使用:字段名 AS 别名
SELECT employee_id AS emp_id, email AS e
FROM employees;
去除重复行:
SELECT DISTINCT 字段名 FROM 表名;
SELECT DISTINCT department_id
FROM departments;
着重号:
``:键盘Tab键上面一个键
适用于字段名等命名与系统方法名(例如:函数名、关键字等)冲突,若不加系统会将字段名判定为方法。
SELECT * FROM `order`;
查询常数:
SELECT 常数,字段名 FROM 表名;
当表中一些数据不存在时可将之添加到字段名前面,这样表中每一行都会添加这个数据。
SELECT '回家', 9, country_id
FROM counties;
显示表结构:
DESC 表名;
DESC countries;
显示表中字段的相关信息。
过滤数据:
SELECT 字段名 FROM 表名 WHERE 过滤条件;
# 查询90号部门中名为king的员工信息
SELECT *
FROM employees
WHERE department_id=90 AND last_name='king';
四、运算符
算术运算符
主要用于数学运算,可以连接运算符前后的两个数值或表达式,对数值或表达式进行+、-、*、/、%运算。
# 将employees表中的salary属性乘以1.2
SELECT salary*1.2 AS income
FROM employees;
# 查询员工id为偶数的员工信息
SELECT *
FROM employees
WHERE employee_id%2=0
注意!SQL中判断相等使用"=“,不能使用”=="!
比较运算符
运算符 | 名称 | 功能 |
---|---|---|
= | 等于运算符 | 判断两个值、字符或表达式是否相等 |
<=> | 安全等于运算符 | 安全地判断判断两个值、字符或表达式是否相等 |
<>或!= | 不等于运算符 | 判断两个值、字符或表达式是否不相等 |
< | 小于运算符 | 判断前值、前面的字符串或表达式是否小于后面 |
<= | 小于等于运算符 | 判断前值、前面的字符串或表达式是否小于或等于后面 |
> | 大于运算符 | 判断前值、前面的字符串或表达式是否大于后面 |
>= | 大于等于运算符 | 判断前值、前面的字符串或表达式是否大于或等于后面 |
除了"<=>"安全等于运算符,其他运算符在有**NULL(空值)**参与时返回值都为NULL。
使用"<=>"运算符时:
若前后两个参数均为NULL,则返回1。
若前后两个参数中有一个为NULL,则返回0。
非字符比较运算符
1、IS NULL、IS NOT NULL、ISNULL()
ISNULL()为函数,判断是否为空。
# 查询commission_pct为NULL的员工信息
SELECT *
FROM employees
WHERE commission_pct IS NULL;
# 或则
SELECT *
FROM employees
WHERE ISNULL(commission_pct);
# 查询commission_pct不为NULL的员工信息
SELECT *
FROM employees
WHERE commission_pct IS NOT NULL;
2、LEAST(value1,…),GREATEST(value1,…)
LEAST():查找最小值
GREATEST:查找最大值
参数可以是列名、常数或表达式,函数将返回这些值中对应的最大值、最小值。
3、BETWEEN 条件1(下限) AND 条件2(上限) 注意:包含了边界!
# 查询工资在6000到9000范围内的员工信息
SELECT *
FROM employees
WHERE salary
BETWEEN 6000 AND 9000;
注意!条件下限一定要在条件上限之前,不然会报错!
当想要查询不在这个区间范围内的信息时,在BETWEEN前面加上NOT即可。
NOT BETWEEN 条件1 AND 条件2
4、IN(set)、NOT IN(set)
**set:**集合数据类型,集合内的元素唯一。
例如:
(10,20,30) 😀
(10,10,20) 😤
# 查询部门编号为10,20,30的员工信息
SELECT *
FROM employees
WHERE department_id IN(10,20,30);
# 查询工资不为6000,7000的员工信息
SELECT *
FROM employees
WHERE salary NOT IN(6000,7000);
5、LIKE:模糊查询
“%”:可代表不确定个数的字符
“_”:可代表一个不确定的字符
# 查询名字中包含"a"的员工信息
# eg:"same"、"laden"、"ada"的信息会被查询到
SELECT *
FROM employees
WHERE last_name LIKE "%a%";
# 查询名字中包含"a"和"e"的员工信息
SELECT *
FROM employees
WHERE last_name LIKE "%a%" AND last_name LIKE "%E%";
# 或则
SELECT *
FROM employees
WHERE last_name LIKE "%a%e%" OR last_name LIKE "%e%a%";
# 查询第2位字母为"a"的员工信息
# eg:"same"会被查到
SELECT *
FROM employees
WHERE last_name LIKE "_a%";
当名字中带有"_"时(例如:“y_ader”),它会被当做占用一个位置的字符,这是需要使用转义符(\)来将他的含义转变。
# 查询第二个字符为"_"且第三个字符为"a"的员工信息
SELECT *
FROM employees
WHERE last_name LIKE "_\_a%";
6、RLIKE(也称REGEXP):正则表达式
“^字符” 匹配以该字符开头的字符串
# 查询名字以"a"开头的员工信息
SELECT *
FROM employees
WHERE last_name RLIKE "^a";
“字符$” 匹配以该字符结尾的字符串
# 查询以"t"结尾的员工信息
SELECT *
FROM employees
WHERE last_name RLIKE "t$";
“.” 匹配任意一个单字符
“[]” 匹配在括号内的任意字符
例如:[0-9]匹配任意数字
“字符*” 匹配任意个在它前面的字符
例如:"x*“匹配任意个x,”[0-9]*"匹配任意个数字。
模糊查询讲解链接
7、逻辑运算符
运算符 | 功能 |
---|---|
NOT 或 ! | 逻辑非 |
AND 或 && | 逻辑与 |
OR 或 || | 逻辑或 |
XOR | 逻辑异或(同0异1) |
8、位运算符
运算符 | 功能 |
---|---|
& | 与运算 |
| | 或运算 |
^ | 异或运算 |
~ | 按位取反 |
>> | 右移 |
<< | 左移 |
五、排序与分页
排序
若没有排序,默认情况下查询返回的数据按照添加数据的顺序显示。
1、ORDER BY 字段名 排序方式; (默认升序排列)
ASC:升序 DESC:降序
# 查询员工信息并按照工资降序排列
SELECT *
FROM employees
ORDER BY salary DESC;
2、使用列的别名作为排序字段名
# 查询一年(月工资*12)工资并降序排列
SELECT salary*12
AS year_salary
FROM employees
ORDER BY year_salary DESC;
3、WHERE需要声明在FROM后面,ORDER BY的前面
# 查询部门编号为30,60,90的员工信息,并按照部门降序排列
SELECT *
FROM employees
WHERE department_id IN (30,60,90)
ORDER BY department_id DESC;
4、多级排序
在对多列进行排序时,首先排序的第一列必须有相同值才会对第二列进行排序。如果第一列得值唯一,将不会对第二列排序。
last_name | department_id | salary |
---|---|---|
张三 | 1 | 9000 |
李四 | 1 | 8000 |
王五 | 3 | 7000 |
刘六 | 2 | 3000 |
钱二 | 2 | 4000 |
赵大 | 1 | 5000 |
在该表中:
张三、李四、赵大的department_id一致,会按照salary的值进行排序。
刘六、钱二的department_id一致,会按照salary的值进行排序。
王五的department_id唯一,不会按照salary排序。
# 显示员工信息,并按照department_id降序,salary升序排列。
SELECT *
FROM employees
ORDER BY department_id DESC,salary ASC;
last_name | department_id | salary |
---|---|---|
王五 | 3 | 7000 |
刘六 | 2 | 3000 |
钱二 | 2 | 4000 |
赵大 | 1 | 5000 |
李四 | 1 | 8000 |
张三 | 1 | 9000 |
分页
1、LIMIT (page-1)*count , count;
每次显示count条信息,显示第page页。
# 显示第二页,每次显示20条
SELECT *
FROM employees
LIMIT (2-1)*20,20;
# 显示第一页,每次显示30条
SELECT *
FROM employees
LIMIT (1-1)*30,30;
2、声明顺序
WHERE => ORDER BY => LIMIT
# 查询工资大于6000的员工信息,降序排列,一页显示30条,显示第一页
SELECT *
FROM employees
WHERE salary>6000
ORDER BY salary DESC
LIMIT 0,30;
六、多表查询的分类
等值查询与非等值查询
等值查询:常用的使用相同键的查询方式
非等值查询:
# 查询员工的last_name,salary,grade_level并按grade_level降序排列
SELECT last_name,salary,grade_level
FROM employee e,job_grade j
WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal
ORDER BY greade_level DESC;
自连接与非自连接
自连接:表的自我引用
# 查询员工id和姓名及其管理者的id和姓名
SELECT emp1.employee_id,emp1.last_name,emp2.employee_id,emp2.last_name
FROM employees emp1,employees emp2
WHERE emp1.manager_id = emp2.employee_id;
非自连接:多个表联表查询
内连接与外连接

但可以使用UNION连接两个查询结果
UNION:返回俩个查询结果集的并集,去除重复记录(占用资源过多,不推荐)
UNION ALL:返回两个查询结果集的并集,不去重。
# 查询employee_id,e-department_id的满连接
# employee表和department表的左外连接加上右外连接去除内连接的部分就是满连接(也可使用UNION链接左外和右外)
# 1.UNION ALL
SELECT employee_id,department_id
FROM employees e LEFT JOIN department d
ON e.department_id = d.department_id
UNION ALL
SELECT employee_id,department_id
FROM employees e RIGHT JOIN department d
ON e.department_id = d.department_id
WHERE e.department_id IS NULL;
# 2.UNION
SELECT employee_id,department_id
FROM employees e LEFT JOIN department d
ON e.department_id = d.department_id
UNION
SELECT employee_id,department_id
FROM employees e RIGHT JOIN department d
ON e.department_id = d.department_id
七、单行函数
流程控制函数
IF(condition,true_value,false_value)
如果condition为TRUE,则返回true_value。
如果condition为FALSE,则返回false_value。
用处:当从数据库中查询出来的结果需要转换成中文或是其他自定义的格式显示在网页上的时候,可以直接在sql中处理。
SELECT
IF(e.department_id = 9,"重要部门","次要部门")
FROM employees AS e;
IFNULL(value1,value2)
如果value1不为NULL(空值),则返回value1的值。
如果value1为NULL,则返回value2的值。
常用在算术表达式计算和组函数中,用来对null值进行转换处理(返回值是数字或者字符串)。
SELECT
IFNULL(e.department_id,"未分配部门")
FROM employees AS e;
if结构:
CASE WHEN 条件1
THEN 结果1
END
if…else结构:
CASE WHEN 条件1
THEN 结果1
ELSE 结果2
END
if…elif…else结构:
CASE WHEN 条件1
THEN 结果1
WHEN 条件2
THEN 结果2
ELSE 结果3
END
switch…case结构:
如果expr的值与WHEN后面的某个常量对应那么就会返回对应的值,都不对应那么就会返回ELSE的值。
CASE expr
WHEN 常量1
THEN 值1
WHEN 常量2
THEN 值2
…
ELSE
值
END
去重关键字:DISTINCT(常在SELECT中使用)
统计一列总和:WITH ROLLUP
聚合函数
1、常见聚合函数
AVG\SUM(只适用于数值类型的字段)
MAX\MIN(适用于数值类型、字符串、日期类型)
COUNT:计算指定字段在查询结构中出现的次数(不包含NULL)
查询表中有多少条数据的方法:
COUNT(*)、COUNT(1)
# 查询共有多少个部门(要求去重)
SELECT
COUNT(DISTINCT e.department_id)
FROM employees AS e;
2、GROUP BY
# 查询各个部门和工种的平均工资
SELECT department_id,job_id,AVG(salary)
FROM employees
GROUP BY department_id,job_id;
SELECT中出现的非聚合函数字段(department_id,job_id)必须声明在GROUP BY中作为分组依据。
3、HAVING(过滤数据)
# 查询各部门中最高工资大于10000的部门信息
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) > 10000;
!!!WHERE和HAVING的区别:如果过滤条件中出现了聚合函数,那么只能使用HAVING。
HAVING必须声明在GROUP BY后面
声明顺序
FROM => WHERE => GROUP BY => HAVING => ORDERY BY => LIMIT
八、子查询
子查询在主查询前一次完成,子查询的结果将被主查询使用。
空值问题:当子查询返回结果中有NULL时,主查询结果为空。
解决办法:在子查询中添加IS NOT NULL过滤空值结果。
子查询分类(根据返回结果的条数分为单行子查询和多行子查询)
1、单行子查询
操作符:=,>,>=,<,<=,<>(!=)
# 查询与141号员工的manager_id,department_id相同的其他员工的相关信息,不包括自己。
SECECT 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;
子查询结果也可结合GROUP BY和HAVING使用。
2、多行子查询
操作符:
IN:等于列表中的任意一个
ANY:需要和单行子查询的操作符一起使用,与子查询的返回结果中某一值进行比较。
ALL:需要和单行子查询的操作符一起使用,与子查询的返回结果中所有值进行比较。
# 查询每个部门工资最低的员工id和姓名
SELECT employee_id,last_name
FROM employees
WHERE salary
IN (SELECT MIN(salary) FROM employees GROUP BY department_id);
# 查询其它job_id中比job_id为"IT_PROG"部门任一工资低的员工id,姓名,job_id,salary
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < ANY
(SELECT salary FROM employees WHERE job_id = "IT_PROG")
AND job_id != "IT_PROG";
# 查询其它job_id中比job_id为"IT_PROG"部门所有工资低的员工id,姓名,job_id,salary
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < ALL
(SELECT salary FROM employees WHERE job_id = "IT_PROG")
AND job_id != "IT_PROG";
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < (SELECT MIN(salary) FROM employees WHERE job_id = "IT_PROG")
AND job_id != "IT_PROG";
!!!MySQL中聚合函数不能嵌套使用,但Oracle可以(如:MIN(AVG(salary)))
# 查询公司平均工资最低的部门
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) =
(SELECT MIN(ret)
FROM (SELECT AVG(salary) AS ret FROM employees GROUP BY department_id) AS ret_table);
!!! 子查询的结果可以作为一张表,但需要将返回结果表取别名
子查询是否被执行多次
1、不相关子查询
以上案例皆为不相关子查询
2、相关子查询
如果子查询的执行依赖于外部查询,通常情况下都是因为子查询用到了外部的表并形成了关联。因此每执行一次外部查询,子查询都要重新计算一次。
# 查询job_history表中调过岗(即相同employee_id的数目和>=2)的员工的id和姓名
SELECT employee_id,last_name
FROM employees e
WHERE 2 <= (SELECT COUNT(1) FROM job_history j WHERE e.employee_id = j.employee_id);
EXISTS与NOT EXISTS关键字
EXISTS:
遍历子查询,若遍历的行不满足条件,则返回False,继续在子查询中寻找。
遍历子查询,若遍历的行满足条件,则返回True,向结果中添加成立(True)的那一行,不再寻找。
NOT EXISTS:
不满足条件的返回True,满足返回False。
# 查询公司管理者的id,last_name
# 1.
SELECT DISTINCT e1.employee_id,e1.last_name
FROM employees e1 JOIN employees e2
ON e1.employee_id = e2.manager_id;
# 2.
SELECT employee_id,last_name
FROM employees
WHERE employee_id IN
(SELECT DISTINCT manager_id FROM employees);
# 3.
SELECT employee_id,last_name
FROM employees e1
WHERE EXISTS
(SELECT * FROM employees e2 WHERE e1.employee_id = e2.manager_id);
九、创建和管理表
创建数据库
1、使用默认字符集创建:
CREATE DATABASE 库名;
2、指定字符集:
CREATE DATABASE 库名 CHARACTER "字符集";
3、查看数据库相关信息:
SHOW CREATE DATABASE 库名;
管理数据库
1、查看数据库列表:
SHOW DATABASES;
2、使用\切换数据库:
USE 库名;
3、查看当前使用的数据库:
SELECT DATABASE() FROM DUAL;
4、查看指定数据库下保存的表:
SHOW TABLES FROM 库名;
删除数据库
DROP DATABASE IF EXISTS 库名;
创建表
1、常用方式
CREATE TABLE 表名 (列名1 数据类型,
列名2 数据类型,
......
列名n 数据类型);
2、给基于现有表查询创建
CREATE TABLE 表名 AS 查询语句;
CREATE TABLE company AS
SELECT employee_id FROM company;
3、查询表结构
DESC 表名;
4、查询表结构
SHOW CREATE TABLE 表名;
修改表:ALTER
1、添加字段
ALTER TABLE 表名 ADD 字段名 数据类型;
2、添加到指定位置
ALTER TABLE 表名 ADD 字段名 数据类型 AFTER 字段名; #添加字段到指定字段名后面
3、修改字段
ALTER TABLE 表名 MODIFY 字段名 数据类型;
4、重命名字段
ALTER TABLE 表名 CHANGE 原字段名 后字段名 数据类型;
5、删除一个字段
ALTER TABLE 表名 DROP 字段名;
重命名表
RENAME TABLE 原表名 TO 后表名;
删除表
DROP TABLE IF EXISTS 表名;
清空表
只清除数据,不删除表结构
方法1:不支持回滚操作(撤销)
TRUNCATE TABLE 表名;
方法2:支持回滚操作
SET autocommit = FALSE; #默认不支持回滚,加上此代码即可支持
DELETE FROM 表名;
DCL(数据库控制语言)中的COMMIT和ROLLBACK
COMMIT:提交数据,执行之后数据会被永久保存在数据库中,不再支持回滚。
ROLLBACK:回滚数据,执行之后可以实现回滚操作,回滚到最近一次COMMIT之后。
# 提交数据
SELECT * FROM company;
COMMIT;
# 清空表
SET autocommit = FALSE;
DELETE FROM company;
# 回滚数据
ROLLBACK;
SELECT * FROM company;
十、数据的增、删、改
插入数据
INSERT INTO 表名 (字段1,字段2...) VALUES (数据1,数据2...);
SELECT语句返回值插入
INSERT INTO 表名1(字段1,字段2)
VALUES (字段1的值, (SELECT 查询字段 FROM 表名2 WHERE 条件));
多行插入
INSERT INTO 表名(字段1, 字段2)
VALUES (字段1数据, 字段2数据),
(字段1数据, 字段2数据),
(字段1数据, 字段2数据);
更新数据
UPDATE 表名 SET 字段1 = 新数据,字段名2 = 新数据 WHERE 过滤条件;
删除数据
DELETE FROM 表名 WHERE 过滤条件;
!!!DML(数据库操作语言)默认酶促执行完自动提交数据(COMMIT操作)
若不需要自动提交,在执行语句前加上"SET autocommit= FALSE"即可。